学习目标: Qt 线程同步
学习前置环境
qt线程同步
Qt提供了丰富的线程同步机制来帮助开发者更高效和安全地进行多线程编程。其主要包括:
-
QMutex:为共享数据提供互斥访问能力,避免同时写入导致的数据冲突。利用lock()/unlock()方法实现锁定和解锁。
-
QReadWriteLock:读写锁,允许多个读线程同时访问,但写操作需要独占锁。适用于读操作频繁,写操作较少的场景。
-
QSemaphore:信号量,用来限制特定资源的访问量。例如一次最多N个线程可以访问缓冲区。通过acquire()/release()实现获取和释放许可。
-
QWaitCondition:条件变量,可以让线程等待一个条件满足后被唤醒。配合QMutex完成更为复杂的同步需求。
-
Qfutures/QtConcurrent:提供了基于线程池的并行计算能力。将耗时任务放入线程池,自动进行并行执行与结果汇总。
-
QEventLoop/Signals&Slots:事件循环与信号槽机制可以实现复杂的线程间通信,例如定时器、Progress Reporting等。
-
QThread:Qt原生的线程类,通过moveToThread()实现在线程间安全地传递QObject。
互斥锁
QMutex / QMutexLocker
QMutex 是 Qt 中用于实现互斥锁的类,用于保证在多线程程序中访问共享资源的互斥性。它提供了两个基本操作:lock() 和 unlock(),分别用于加锁和解锁。
QMutexLocker 是 QMutex 的 RAII 风格封装,可以自动释放锁资源,避免忘记解锁而导致的死锁情况。QMutexLocker 在创建时会自动调用 QMutex 的 lock() 方法,析构时会自动调用 QMutex 的 unlock() 方法。因此使用 QMutexLocker 可以大大减少忘记解锁的情况。
QMutex mutex;
void func() {
{
QMutexLocker locker(&mutex);
//临界区域
}
mutex.lock();
//临界区域
mutex.unlock();
}
互斥锁实现买票同步程序
此处实现多线程重写版完美退出机制
#ifndef SELLER_H
#define SELLER_H
#include<QThread>
#include<QMutex>
#include<QDebug>
class seller :public QThread
{
Q_OBJECT
public:
seller()=default;
seller(int* data,QMutex *m){
tickets=data;
mtx=m;
}
signals:
void ticketsFinsh();
public:
void run() override{
while ((*tickets) > 0) { //多线程经典问题 双锁机制
mtx->lock();
if((*tickets) > 0){
mtx->unlock();
mtx->lock();
qDebug()<<this->objectName()<<" : " <<--(*tickets);
mtx->unlock();
QThread::usleep(100);
}
}
ticketsFinsh();
}
private:
int* tickets; // 票
QMutex *mtx;
};
#endif // SELLER_H
#include <QCoreApplication>
#include"seller.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int tickets =100;
QMutex mtx;
seller* t1 =new seller(&tickets,&mtx);
seller* t2 =new seller(&tickets,&mtx);
seller* t3 =new seller(&tickets,&mtx);
t1->setObjectName("Thread 1");
t2->setObjectName("Thread 2");
t3->setObjectName("Thread 3");
//设置线程完成信号与主线程进行连接,主线程知道子线程任务结束。
QObject::connect(t1, &seller::finished, t1, &seller::quit);
QObject::connect(t2, &seller::finished, t2, &seller::quit);
QObject::connect(t3, &seller::finished, t3, &seller::quit);
//线程对象在离开线程后删除,但不代表线程任务真正完成。
QObject::connect(t1, &seller::finished, t1, &seller::deleteLater);
QObject::connect(t2, &seller::finished, t2, &seller::deleteLater);
QObjec