Qt5 Tutorial QThreads - QMutex - 2020
In this tutorial, we will learn how to sync threads using QMutex.
The QMutex class provides access serialization between threads.
The purpose of a QMutex is to protect an object, data structure or section of code so that only one thread can access it at a time (synchronized). It is usually best to use a mutex with a QMutexLocker since this makes it easy to ensure that locking and unlocking are performed consistently.
QMutex::QMutex(RecursionMode mode = NonRecursive)
The QMutex() constructs a new mutex. The mutex is created in an unlocked state. If mode is QMutex::Recursive, a thread can lock the same mutex multiple times and the mutex won't be unlocked until a corresponding number of unlock() calls have been made. Otherwise a thread may only lock a mutex once. The default is QMutex::NonRecursive.
enum QMutex::RecursionMode
Constant | Value | Description |
---|---|---|
QMutex::Recursive | 1 | In this mode, a thread can lock the same mutex multiple times and the mutex won't be unlocked until a corresponding number of unlock() calls have been made. |
QMutex::NonRecursive | 0 | In this mode, a thread may only lock a mutex once. |
We'll starting from Qt Console Application.
A couple of lines have been changed from QThreads - Creating Threads.
In this example, we introduced a boolean public member variable Stop to control thread behavior. If it is set as true, a thread will be jump out of the loop. So, it needs to be accessed by only one thread, and we use mutex locking mechanism.
main.cpp:
#include <QCoreApplication> #include "mythread.h" #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // creating three thread instances MyThread thread1("A"), thread2("B"), thread3("C"); qDebug() << "hello from GUI thread " << a.thread()->currentThreadId(); // thread start -> call run() thread1.start(); thread2.start(); thread3.start(); return a.exec(); }
mythread.h:
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread> #include <QString> class MyThread : public QThread { public: // constructor // set name and Stop is set as false by default MyThread(QString s, bool b = false); // overriding the QThread's run() method void run(); // variable that mutex protects bool Stop; private: QString name; }; #endif // MYTHREAD_H
mythread.cpp:
#include "mythread.h" #include <QDebug> #include <QMutex> MyThread::MyThread(QString s, bool b) : name(s), Stop(b { } // run() will be called when a thread starts void MyThread::run() { qDebug() << this->name << " " << this->Stop; for(int i = 0; i <= 5; i++) { QMutex mutex; // prevent other threads from changing the "Stop" value mutex.lock(); if(this->Stop) break; mutex.unlock(); qDebug() << this->name << " " << i; } }
Though there could be some performance hits because of QMutex creation and the calls to lock() and unlock(), the output shows any significant changes in terms of threads' behavior.
hello from GUI thread 0x1364 "A" false "C" false "C" 0 "A" 0 "A" 1 "A" 2 "A" 3 "A" 4 "C" 1 "A" 5 "B" false "C" 2 "C" 3 "C" 4 "C" 5 "B" 0 "B" 1 "B" 2 "B" 3 "B" 4 "B" 5
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization