Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 2017

    @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 2017

    @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 2017

    @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