QT:Qt多线程同步

来源:互联网 发布:sqlserver下载 64位 编辑:程序博客网 时间:2024/05/16 09:41

QT多线程同步

1 )互斥锁QMutex
 保证同一时刻有指定多个线程访问共享资源。
 void lock( );
 void unlock( );


/** eg代码演示 **/

 int g_count = 0; // 临界资源(全局变量) void ThreadA::run ( ) {  g_count++; } void ThreadB::run ( ) {  g_count++; }  // g_count 大部分是2,有时为1BUG:'AB两个线程占用CPU资源的先后顺序有不确定的可能性',有bug可能【解决方法】 QMutex mutex; int g_count = 0;  void ThreadA::run ( ) {  mutex.lock ( ); // 锁定成功立即返回,失败则阻塞,等待另一个  g_count++;   mutex.unlock ( ); } void ThreadB::run ( ) {  mutex.lock ( ); // 加锁失败,原地等待-直到第一个线程调用了unlock ( )  g_count++;   mutex.unlock ( );  }  // g_count正确结果必定是2

2 ) 读写锁QReadWriteLock   
 QReadWriteLock lock;
 int data;
 void ReadThread::run (void) {
  lock.lockForRread ( );
  access_data_without_modity (&data); // 访问可以,不能修改 (逻辑)
  lock.unlock ( );
 }
 void WriteThread::run (void) {
  lock.lockForWrite ( );
  modity_data (&data); // 写锁在逻辑上就只是为了修改
  lock.unlock ( );
 }

3 ) 信号量:QSemaphore   UC - QT - 内核编程 - win32:信号量都一样
提供了一个通用的技术信号量,保证同一时刻有指定多个线程访问共享资源。

'PV操作'  <==>  信号量是干什么用的?
P:申请资源,将信号量 - 1 ,S = S - 1  --->
  减1以后如果S >= 0,该进程或线程继续执行,否则(S < 0)进入等待
 'S:信号量,比如S为-2,说明有2个线程在等待/阻塞'
V:释放资源,将信号量 + 1 ,S = S + 1  --->
  加1以后如果S > 0,什么都不做,代码则继续执行
  加1以后如果S <= 0,说明有进程或线程正在等待/阻塞,加1时唤醒一个等待的进程或线程,唤醒哪一个线程在linux系统上是不确定的。
【总结】原语:原子性操作,保证线程执行是一定不会发生CPU资源切换

 // P: 获取信号量
 void acquire(int n = 1);
 // V: 释放信号量
 void release(int n = 1);

《案例》生产者与消费者
定义两个信号量:
 freeSpace: 控制生产者线程,如果仓库满,则阻塞等待;
 usedSpace: 控制消费者线程,如果仓库空,则阻塞等待;

生产者:
 while (1) {
  P (freeSpace);
  // 生产一个产品,放入仓库
  V (usedSpace);
 }

消费者:
 while (1) {
  P (usedSpace);
  // 从仓库取出一个产品消费使用
  V (freeSpace);
 }

/** 代码演示  - 信号量实现**/

#include <QCoreApplication> // 它是QApplication的基类,没有图形界面的程序声明头文件#include <QThread>#include <QSemaphore>const int DataSize = 10; // 要生产的产品总量const int BufferSize = 5; // 存放产品的仓库大小int Buffer[BufferSize]; // 仓库// 控制生产者的信号量QSemaphore freeSpace (BufferSize);// 控制消费者的信号量QSemaphore usedSpace (0);// 生产者线程class threadProducer : public QThread {public:    void run (void) {        for (int i = 0; i < DataSize; i++) {            // P 操作-1,获取信号量成功,仓库有空位,则生产1个            freeSpace.acquire ();            Buffer[i % BufferSize] = i + 1; // Buffer[i % BufferSize],轮循(环形队列)            qDebug ("Producer: %d", Buffer[i % BufferSize]);            // V 操作+1,仓库中有可消费的产品,消费数量+1            usedSpace.release ();            msleep (300);        }    }};// 消费者线程class threadConsumer : public QThread {public:    void run (void) {        for (int i = 0; i < DataSize; i++) {            // P 操作-1,仓库有可消费的产品,则消费1个            usedSpace.acquire ();            qDebug ("Consumer: %d", Buffer[i % BufferSize]);            // V 操作+1,仓库中空闲位置多出1个,就可生产数量+1            freeSpace.release ();            msleep (500);        }    }};int main (int argc, char** argv) {    // QT核心应用程序,不包含ui    QCoreApplication app (argc, argv);    threadProducer producer;    threadConsumer consumer;    producer.start ();    consumer.start ();    producer.wait ();    consumer.wait ();    return app.exec ();}

4 ) 条件等待:QWaitCondition     ---> 相当于UC中的条件变量
解决生产者消费者问题,使用条件等待(条件变量)更适用。
 // 阻塞当前线程,解锁
 bool wait(QMutex * lockedMutex);
 // 唤醒所有阻塞的线程
 void wakeAll( );

《案例》生产者与消费者  - 条件等待(变量)
【生产条件】缓冲区不满则生产,否则等待;
 QWaitCondition bufferIsNotFull;
【消费条件】缓冲区不空则消费,否则等待;
 QWaitCondition bufferIsNotEmpty;

/** 代码演示 - 条件等待(变量)实现 **/

#include <QCoreApplication>#include <QWaitCondition>#include <QMutex>#include <QThread>const int DataSize = 10; // 生产的产品总量const int BufferSize = 5; // 仓库的大小int buffer[BufferSize]; // 仓库// 生产条件:仓库不满则生产QWaitCondition bufferIsNotFull;// 消费条件:仓库不空则消费QWaitCondition bufferIsNotEmpty;// 互斥锁QMutex mutex;// 记录当前仓库的产品数量int usedSpace = 0;// 生产者线程类class threadProducer : public QThread {public:    void run (void) {        for (int i = 0; i < DataSize; i++) {            mutex.lock ();            while (usedSpace == BufferSize) {                // 仓库满,则生产者阻塞等待                bufferIsNotFull.wait (&mutex);            }            // 仓库不满,开始生产++            buffer[i % BufferSize] = i + 1;            qDebug ("Producer: %d", buffer[i % BufferSize]);            ++usedSpace; // 记录产品个数 + 1            // 唤醒消费者线程,让消费这可以开始消费产品            bufferIsNotEmpty.wakeAll ();            mutex.unlock ();            msleep (300);        }    }};// 消费者线程类class threadConsumer : public QThread {public:    void run (void) {        for (int i = 0; i < DataSize; i++) {            mutex.lock ();            while (usedSpace == 0) {                // 仓库为空,则消费者阻塞等待                bufferIsNotEmpty.wait (&mutex);            }            // 仓库不空,开始消费--            qDebug ("Consumer: %d", buffer[i % BufferSize]);            --usedSpace;            // 唤醒生产者线程,让生产者可以开始生产产品            bufferIsNotFull.wakeAll ();            mutex.unlock ();            msleep (700);        }    }};int main (int argc, char** argv) {    QCoreApplication app (argc, argv);    threadConsumer consumer;    threadProducer producer;    producer.start ();    consumer.start ();    producer.wait ();    consumer.wait ();    return app.exec ();}


<tips>
mkdir 目录
cd 目录
touch main.cpp
qmake -project
qtcreator &  // 在QT中打开 open project,找到目录

0 0
原创粉丝点击