Qt多執行緒同步
一、Qt中使用多執行緒時候,多執行緒的同步就是一個不可避免的問題。多執行緒的同步就是使多個執行緒在同時執行同一段程式碼的時候,有順序的執行,不會出現同時有兩個或者多個執行緒執行同一段程式碼的情況,特別是在對變數或者檔案執行寫操作的時候。也就是所謂的執行緒安全,執行緒安全指的是這段程式碼在一個執行緒或者多個執行緒執行的過程中,不加同步機制或者任何其他程式碼,執行的結果是一樣的,這就是執行緒安全。 在Qt中常用的同步方法是使用鎖機制,但是如果使用的方法不對或者時機不對同樣也不會起到執行緒同步的效果。例如: 執行緒類:
#pragma once
#include <QThread>
#include <QMutex>
class MyThread : public QThread {
Q_OBJECT
public:
MyThread(QObject *parent);
~MyThread();
void run();
private:
QMutex mutex;
};
#include "MyThread.h"
#include <QDebug>
static int cnt = 0;
MyThread::MyThread(QObject *parent)
: QThread(parent) {
}
MyThread::~MyThread() {
}
void MyThread::run() {
while(true) {
msleep(500);
mutex.lock();
cnt += 1;
qDebug() << cnt<<":"<<this->currentThreadId();
mutex.unlock();
}
}
介面類:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_MultiThread.h"
class MyThread;
class MultiThread : public QMainWindow {
Q_OBJECT
public:
MultiThread(QWidget *parent = Q_NULLPTR);
private:
Ui::MultiThreadClass ui;
MyThread* thread1 = nullptr;
MyThread* thread2 = nullptr;
};
#include "MultiThread.h"
#include "MyThread.h"
MultiThread::MultiThread(QWidget *parent)
: QMainWindow(parent) {
ui.setupUi(this);
thread1 = new MyThread(this);
thread2 = new MyThread(this);
thread1->start();
thread2->start();
}
以上是兩個執行緒同時對同一個靜態變數進行寫操作。 開始執行,然後檢視列印結果: 怎麼兩個同時執行的執行緒,出來的相同的結果,難道執行緒同步沒有起作用?這是怎麼回事? 仔細一想發現了問題,原來是雖然添加了兩個執行緒物件,但是每個執行緒物件都建立了一個QMutex物件,兩個執行緒在執行過程中各自執行的是自己的鎖,所以每個鎖有且只有一個執行緒在執行。它們是互不干擾的,所有雖然加鎖了,也沒有起到同步的作用,那麼如果讓鎖發揮作用呢?修改一下程式碼,讓兩個執行緒使用同一個鎖:
#pragma once
#include <QThread>
#include <QMutex>
class MyThread : public QThread {
Q_OBJECT
public:
MyThread(QObject *parent);
~MyThread();
void run();
};
#include "MyThread.h"
#include <QDebug>
static int cnt = 0;
static QMutex mutex;
MyThread::MyThread(QObject *parent)
: QThread(parent) {
}
MyThread::~MyThread() {
}
void MyThread::run() {
while(true) {
msleep(500);
mutex.lock();
cnt += 1;
qDebug() << cnt<<":"<<this->currentThreadId();
mutex.unlock();
}
}
然後在執行一下,這樣結果就正確了,結果沒有出現重複的,實現了執行緒同步:
二、還可以使用QMutexLocker類實現鎖同步機制。 Qt提供的QMutexLocker可以簡化互斥量的操作,它在建構函式中接受一個QMutex的物件作為引數並將其鎖定,在解構函式中解鎖這個互斥量,也是很方便的,咱們在同時修改一下程式碼:
#include "MyThread.h"
#include <QDebug>
static int cnt = 0;
static QMutex mutex;
MyThread::MyThread(QObject *parent)
: QThread(parent) {
}
MyThread::~MyThread() {
}
void MyThread::run() {
while(true) {
msleep(500);
QMutexLocker locker(&mutex);
cnt += 1;
qDebug() << cnt<<":"<<this->currentThreadId();
}
}
那麼這個訊號量保護的是哪一部分程式碼呢?while迴圈結束。因為QMutexLocker物件是一個臨時的區域性物件,當迴圈完成之後,這個物件也就釋放了,同時也就解鎖了。執行一下! 同樣也是沒有重複的資料。以上!