How to start/pause/resume/stop Qt thread?

If you’ve read my post Qt Thread, you should be able to run a task in a new thread now. But you may always want to do some controls on the new thread such as pausing it/resuming it/stopping it.

How to start a Qt Thread?

This would be the easiest thing compared to pausing/stopping a Qt thread. You just call QThread::start function, the thread will be started immediately. The best part is if the thread has already be started and running, the function does nothing so you do not need to worry it will restart your task.

How to pause a Qt Thread?

If you are familiar with Windows API, you must know the API to pause/suspend a Windows thread is SuspendThread(HANDLE hThread). The API to resume/continue a Windows thread is ResumeThread(HANDLE hThread). QThread has no such function to pause/resume it. But you can do some hack to use native Windows API to do it:

  1. Get the native thread id of the QThread object:
    Qt::HANDLE qthandle=QThread::currentThreadId();

    Note that currentThreadId() is a static function which returns the id of the calling thread.

  2. Convert the thread id to thread handle:
    HANDLE threadhandle=::OpenThread(dwDesiredAccess,bInheritHandle,(DWORD) qthandle);
  3. Suspend/resume the thread by the handle:
    ::SuspendThread(threadhandle);
    ::ResumeThread(threadhandle);

This method has one apparent limitation that it can only be used on Windows platform. Another problem about this method is that the thread can be paused at any point which may cause undesirable effects. For example, if you are connected with a server while the thread is paused, the server may disconnect you for long idle.

So, directly pausing a thread without letting it even know is not a good idea. You should embed some code at chosen safe places in your thread task to pause according to some flag set externally.

void yourtaskfunction()
{
    while(...)
    {
           do some work
           sync.lock();
           if(pauseflag)
           {
               pauseCond.wait(&sync);
           }
           sync.unlock();
           do other work
    }
}

Here, your thread function does a task in a loop that’s time-consuming. We insert a piece of code in between the task. The code waits for a QWaitCondition object pauseCond if the pauseflag was set, which actually lets the thread sleep(pause). How to wake it up later? The sleeping thread cannot wake itself up apparently. You need to wake it up in another thread at appropriate time.

sync.lock();
pauseflag = false;
sync.unlock();
pauseCond.wakeAll();

The code setting the pauseflag is:

sync.lock();
pauseflag = true;
sync.unlock();

You may wonder why we use a QMutex sync. Well, this is a convention in multi-thread programming because pauseflag can be read/written in multiple threads, the QMutex can ensure it can only be accessed by one thread at a time. This is not important in this case. You can omit the QMutex and there would be not much difference.

If you are not comfortable in using QMutex, etc., you can use the code in this post which does not use a locker.

 How to stop a thread?

The QThread::terminate function is highly discouraged because it can kill your thread at any execution point.

You may find QThread::exit or QThread::quit(equivalent to QThread::exit(0)), which seem to stop a thread. But the official document only says they let the thread exits from the event loop, not saying they will stop the thread. If your thread is not being in an event loop, the functions have no effect.  The default implementation of QThread::run has an event loop. If the thread is being in that event loop, after QThread::quit is called, it will exit that event loop and run returns. After QThread::run returns, the thread is finished. (refer to this post).

So, if your thread is executing its own task and is not  in an event loop, you need to add some code to your thread task to stop the thread according to a flag, like we have done for pausing a thread.

void yourtaskfunction()
{
    while(...)
    {
        do some work
        if(stopflag)
            break;
       do some work;
    }
    emit finished();
}

You should connect the finished signal to QThread::quit() slot so the the thread can be stopped.

If you like my content, please consider buying me a coffee. Buy me a coffeeBuy me a coffee Thank you for your support!
Posted in

Leave a Reply