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 your run() implementation. If not maybe you can use some timers to repeatedly check the m_running flag (- i have to mention that a QTimer 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



  • @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.


  • Qt Champions 2016

    @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 worker QObject 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 with QRunnable, 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 the QRunnable. As i said in my previous post I will try to create small test app for this case.


  • Qt Champions 2016

    @voltron
    Right, only you wouldn't handle the signal as Qt::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 :-)


  • Qt Champions 2016

    @ttuna
    Thanks, I couldn't claim credit though. It's used extensively in the reference counting mechanism in Qt (i.e. for implicit sharing, smart pointers and so on). :)



  • @kshegunov
    Thanks a lot! I modified your example a bit to use QMutex to protect flag when changing it. Need to use QMutex because in PyQt4 there is no QAtomicInt.
    Thanks again for your help.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.