Solved Non-Reentrant Class Use In Multithreaded Program
-
From the looks of it, since it's a blocking call, it should be safe. However, I'd recommend that you put a comment in your code explaining this.
-
I'm implementing the callback now but am having a simple issue.
DWORD Worker::copyProgress(LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred, LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred, DWORD streamNo, DWORD callbackReason, HANDLE src, HANDLE dst, LPVOID data) { Worker *thisWorker = qobject_cast<Worker *>(data);
compiler complains:
C2665: 'qobject_cast': none of the 2 overloads could convert all the argument types could be 'T *qobject_cast<Worker*>(const QObject *)' or 'T *qobject_cast<Worker*>(QObject *)' while trying to match the argument list '(LPVOID)'
What's up with this guy? Google didn't show much info...
-
Found what I was looking for...
https://stackoverflow.com/questions/39592202/converting-between-qobject-and-void -
Another obstacle to overcome - the CopyFileEx function only accepts LPBOOL, which is
typedef BOOL far *LPBOOL; and typedef int BOOL;,
so I can't use my volatile std::atomic_bool cancel I was using before. What's the best way to solve this problem? Do I have to use a normal non-atomic LPBOOL to pass to the CopyFileEx function? If so do I need to use a mutex for the cancel bool that allows me to cancel the file copy logic when requested? If so where do I put the mutexes? Thanks. Here's the current code.class Worker : public QObject { public: void stop() { cancel = true; } volatile std::atomic_bool cancel; ... void Replicator::stopWork() { if (isBusy) worker->stop(); }
-
@Crag_Hack said in Non-Reentrant Class Use In Multithreaded Program:
CopyFileEx
It's not the same variable, don't mix stoping your Worker with Stoping CopyFileEx.
-
But I need to be able to stop the worker thread from the gui thread, not just when the program is scanning files but also when it is copying files, using the same cancel condition as created by clicking the cancel button in the gui thread. All the logic is handled in the worker thread both scanning, volume shadow copy service, file copying and everything. All of these operations need to be cancelled if desired. The worker thread remains alive it just gets reused for each backup that is performed. I did just find a workaround as per your suggestion got my creative juices flowing... I can check the std::atomic_bool cancel variable in the CopyFIleEx progress callback function and if it is true then return PROGRESS_CANCEL. Can you think of another way to do this though? Just curious.
-
@Crag_Hack said in Non-Reentrant Class Use In Multithreaded Program:
I can check the std::atomic_bool cancel variable in the CopyFIleEx progress callback function and if it is true then return PROGRESS_CANCEL. Can you think of another way to do this though?
This sounds like a decent plan to me.
-
Will this code maintain the atomicity of the cancel variable? And should I declare cancel volatile? I'm guessing std:atomic_bool will make that unncecessary...
class Worker : public QObject { bool getStop() { return cancel; } volatile std::atomic_bool cancel; ... DWORD Worker::copyProgress(LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred, LARGE_INTEGER, LARGE_INTEGER, DWORD, DWORD, HANDLE, HANDLE, LPVOID data) { Worker *worker = static_cast<Worker *>(data); if (worker->getStop()) return PROGRESS_CANCEL;
-
@Crag_Hack said in Non-Reentrant Class Use In Multithreaded Program:
Will this code maintain the atomicity of the cancel variable?
Yes, of course.
And should I declare cancel volatile?
No, no reason to do that. Forget volatile, especially if you're not intimately familiar with what it does. It's very special and here there is no a proper reason to use it.
I'm guessing std:atomic_bool will make that unncecessary...
That is correct.
volatile
means something quite different anyway, it doesn't provide atomicity at all. -
Thanks! Almost time to go live!