How to call a non-class member function with pointers as parameters with QtConcurrent::run?

254 Views Asked by At

I want to call a recursive non-class member function used to erase a given folder with all of its files using Qt 4.8 for Embedded Linux:

bool removeFiles(const QString & dirName, Interface::ProgressDialog* const poProgressDialog, qint32* const itemDeletedCounter)
{
    bool result = true;

    try
    {
        QDir dir(dirName);

        if (dir.exists(dirName))
        {
            Q_FOREACH (QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden  | QDir::AllDirs | QDir::Files, QDir::DirsFirst))
            {
    //            if (Q_UNLIKELY(poProgressDialog->wasCanceled()))
    //                break;

                if (info.isDir())
                    result = removeFiles(info.absoluteFilePath(),poProgressDialog,itemDeletedCounter);
                else
                {
                    result = QFile::remove(info.absoluteFilePath());

                    try
                    {
                        poProgressDialog->setValue(*itemDeletedCounter);
                    }
                    catch (...)
                    {
                        const QString strTemp = QString("Error in removeFiles::poProgressDialog->setValue(*itemDeletedCounter); !!!");

                        mDebugS(strTemp);
                        mLog(strTemp);
                    }

                    ++(*itemDeletedCounter);
    //                mDebugS(QString("%1").arg(itemDeletedCounter));
                }

                if (!result)
                    return result;
            }

            result = dir.rmdir(dirName);
        }
    }
    catch (...)
    {
        const QString strTemp = QString("General error in removeFiles");

        mDebugS(strTemp);
        mLog(strTemp);
    }

    return result;
}

(Forget the try-catches; they were for "debug")

As you can see, this function receives as parameters both a pointer to a QProgressDialog-like class as well as a pointer to an integer. The QProgressDialog-like class updates the interface with the progress of the delete operation and the integer stores the actual number of files removed.

The problem I'm having is that I constantly get segmentation faults, alignment traps and the like when I call this function using QtConcurrent::run:

concurrentResp = QtConcurrent::run(removeFiles, QString(DEFAULT_RECORD_DIR), poDialog, &itemCounter);

The same doesn't happen when I call the function directly, so I know it's probably not a problem with the function or with the ProgressDialog class. And I don't have GDB accessible to more carefully debug this (thanks to that GDB with Python stuff).

So my question is essentially: what am I doing wrong? And how should I do this without errors?

Extra info:

  • As for now both the ProgressDialog and the integer are global in the .cpp file, but they were local some time ago and the problem already existed.
  • Sometimes the seg fault only appears when closing the app in the "return" function at the end of main(). As it is now, though, problems are appearing even before finishing the clear operation.
3

There are 3 best solutions below

2
On BEST ANSWER

The GUI can be updated only from the main thread.

You are trying to update your dialog from another thread.

Try this

QMetaObject::invokeMethod(poProgressDialog, "setValue",
                          Qt::AutoConnection,
                          Q_ARG(qint32, *itemDeletedCounter));

instead of this :

poProgressDialog->setValue(*itemDeletedCounter);
0
On

In general you should not modify a UI component directly from a background thread, this is what you are doing when you call poProgressDialog->setValue(*itemDeletedCounter); from a method that is executed with QtConcurrent::run(...).

There is a tutorial here on how to use QtConcurrency with QProgressDialog. It basically involves using the QFutureWatcher class to monitor a process in a thread-safe way using signals and slots.

1
On

The best approach is to create respective QObject for such tasks. This way most of mutineering issues can be solved by signal slot mechanism. Also you will separate UI from actual work (what is always recommended).

Progress of task you should be reported by emitting signals which you will connect to respective slots of UI objects.