0

I am multithreading my Qt data backup program with all file manipulation logic offloaded to a worker object that has been moved to a worker thread. I am wondering if it is safe to use CopyFileEx to do the file copying within the worker thread.

The one most relevant detail I'm not sure about is that I pass the CopyFileEx call a callback function as the lpProgressRoutine parameter. This callback function is a static DWORD CALLBACK member of the worker object. Is this safe and avoids race conditions even though the callback is static? The QThread::currentThreadId() call within the callback reports the same thread as the worker thread.

Also I pass the worker object as this to the lpData parameter so I can access worker object member functions from within the callback function which connect to the main gui thread via signals/slots to update the gui on copy progress.

Anything else worth noting? Here is the code:

//code within main gui thread to create worker object and move to worker thread
workerThread = new QThread(this);
workerThread->start();
worker = new Worker;
worker->moveToThread(workerThread);
//here is the CopeFileEx call for copying files in a worker object method
if (!CopyFileEx(sourceFile.fileName().toStdWString().c_str(), targetTempFile.fileName().toStdWString().c_str(), &copyProgress, this, NULL, 0))
    win32Error(TEXT("CopyFileEx"));
//here is the declaration of the static DWORD CALLBACK function to pass as a callback to CopyFileEx
class Worker : public QObject
{
    Q_OBJECT
public:
    static DWORD CALLBACK copyProgress(
             LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred,
             LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred,
             DWORD streamNo, DWORD callbackReason, HANDLE src, HANDLE dst,
             LPVOID data);
//here is the callback function implementation
DWORD Worker::copyProgress(LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred, LARGE_INTEGER, LARGE_INTEGER, DWORD, DWORD, HANDLE, HANDLE, LPVOID data)
{
    qDebug() << "copyprogress" << QThread::currentThreadId() << "transferred" << totalTransferred.QuadPart;

    Worker *worker = static_cast<Worker *>(data);

    if (worker->getStop())
        return PROGRESS_CANCEL;

    qint64 readSize = totalTransferred.QuadPart - worker->prevBytesTransferred;
    worker->prevBytesTransferred = totalTransferred.QuadPart;
    worker->setProgressMeters(readSize, totalSize.QuadPart);
    worker->setTimeLabels(readSize);

    return PROGRESS_CONTINUE;
}
riverofwind
  • 525
  • 4
  • 17
  • all what you need - your object (instance of `Worker`) must be valid during `CopeFileEx`. the `copyProgress` callback called in the same thread, which call `CopeFileEx` despite this is not documented – RbMm Sep 02 '19 at 21:26
  • This [case](https://stackoverflow.com/questions/19136936/copyfileex-with-progress-callback-in-qt) gives a sample. You can refer to. – Jeffreys Sep 03 '19 at 10:00
  • Thanks guys. Sounds like I'm good to go. – riverofwind Sep 04 '19 at 03:35

0 Answers0