QRunnable and QThreadPool: how to interrupt the task?
-
I trying to identify the best approach to use for my PyQt application. The program has multiple independent data-processing tools which I want to run in separate threads to keep GUI responsive and allow user to process several datasets at once.
As I understand, I can use QThreads + worker objects + my own thread queue implementation or alternatively use QThreadPool and QRunnables. I already found how I can emit signals from QRunnable (e.g. to report progress or show messages), but I can not find is it possible to interrupt QRunnable?
Ability to interrupt is really necessary as some processes may be very long-running and users should have ability to stop them. So my question is: can I interrupt QRunnable and if yes, how to do it?
Thanks for your replies.
-
Multithreading Technologies in Qt
At the bottom you can find a table 'Choosing an Appropriate Approach'. Hope this will help you. -
#yolo - have some time to spare so here is the longer answer :-)
If your QRunnable derived object lives (- is created) in a thread with event loop, you can implement a slot to access a flag (-lets call it
bool m_running
).In your
run()
method you can check on this flag and leave if .e.g.m_running == false
.
I don't know if you have a loop in yourrun()
implementation. If not maybe you can use some timers to repeatedly check the m_running flag (- i have to mention that aQTimer
needs a event loop!!!)Maybe you will have to implement some QMutex for your flag, because you are accessing it from two (-or more) threads.
BR
-
Multithreading Technologies in Qt
At the bottom you can find a table 'Choosing an Appropriate Approach'. Hope this will help you.@ttuna thanks for your reply.
I already read documentation mentioned by you. My use case is similar to "One call" so both approaches: QThread or QRunnable should be fine.
Also I need to need to update progress/cancel operation and again both approaches can do this. QThread can emit and accept signals, QRunnable — can not. But with QRunnable I can have dummy QObject for emmiting signals. The only thing I miss with QRunnable is the ability to stop it.Thanks for the hint with bool flag, I will look if it is possible to implement it.
-
@ttuna thanks for your reply.
I already read documentation mentioned by you. My use case is similar to "One call" so both approaches: QThread or QRunnable should be fine.
Also I need to need to update progress/cancel operation and again both approaches can do this. QThread can emit and accept signals, QRunnable — can not. But with QRunnable I can have dummy QObject for emmiting signals. The only thing I miss with QRunnable is the ability to stop it.Thanks for the hint with bool flag, I will look if it is possible to implement it.
@voltron
Hello,The only thing I miss with QRunnable is the ability to stop it.
Right, so how do you stop
QThread
? Think about it,QRunnable
is an atomic task that should be executed on a free thread from the pool. Then if you're using a workerQObject
your atomic tasks are the slots that are executing. For the worker object you also have no way of stopping the thread mid-processing, aside from manually synchronizing a flag that tells you you have to stop doing what you're doing and setting it through a direct call from the outside. But in the end this should be possible withQRunnable
, no?Kind regards.
-
@voltron
Hello,The only thing I miss with QRunnable is the ability to stop it.
Right, so how do you stop
QThread
? Think about it,QRunnable
is an atomic task that should be executed on a free thread from the pool. Then if you're using a workerQObject
your atomic tasks are the slots that are executing. For the worker object you also have no way of stopping the thread mid-processing, aside from manually synchronizing a flag that tells you you have to stop doing what you're doing and setting it through a direct call from the outside. But in the end this should be possible withQRunnable
, no?Kind regards.
@kshegunov thanks a lot for your reply.
Usually, when I use
QThread
for long running task I have a loop inside thread or worker object where all data-processing happens. And before each iteration I just check bool flag "interrupt" and break loop if this flag is set.I never used
QRunnable
before so I don't know if it is possible to change flag from outside, e.g. by emitting a signal in the GUI thread and handling it in theQRunnable
. As i said in my previous post I will try to create small test app for this case. -
@kshegunov thanks a lot for your reply.
Usually, when I use
QThread
for long running task I have a loop inside thread or worker object where all data-processing happens. And before each iteration I just check bool flag "interrupt" and break loop if this flag is set.I never used
QRunnable
before so I don't know if it is possible to change flag from outside, e.g. by emitting a signal in the GUI thread and handling it in theQRunnable
. As i said in my previous post I will try to create small test app for this case.@voltron
Right, only you wouldn't handle the signal asQt::QueuedConnection
as it's usually done. Consider this very simple example:class MyRunnable : public QRunnable { public: void requestInterruption() { interrupt.testAndSetOrdered(0, 1); } bool isInterruptionRequested() const { return static_cast<int>(interrupt); } private: QAtomicInt interrupt; };
Then call the functions how you'd usually do with
QThread
.Kind regards.
-
@voltron
Right, only you wouldn't handle the signal asQt::QueuedConnection
as it's usually done. Consider this very simple example:class MyRunnable : public QRunnable { public: void requestInterruption() { interrupt.testAndSetOrdered(0, 1); } bool isInterruptionRequested() const { return static_cast<int>(interrupt); } private: QAtomicInt interrupt; };
Then call the functions how you'd usually do with
QThread
.Kind regards.
@kshegunov
Atomic flag ... nice idea :-) -
@kshegunov
Atomic flag ... nice idea :-) -
@voltron
Right, only you wouldn't handle the signal asQt::QueuedConnection
as it's usually done. Consider this very simple example:class MyRunnable : public QRunnable { public: void requestInterruption() { interrupt.testAndSetOrdered(0, 1); } bool isInterruptionRequested() const { return static_cast<int>(interrupt); } private: QAtomicInt interrupt; };
Then call the functions how you'd usually do with
QThread
.Kind regards.
@kshegunov
Thanks a lot! I modified your example a bit to useQMutex
to protect flag when changing it. Need to useQMutex
because in PyQt4 there is noQAtomicInt
.
Thanks again for your help.