解析 QT 多线程程序详细设计 上篇
创始人
2024-08-01 11:31:16
0

QT 多线程程序详细设计是本文要介绍 的内容,关于多线程的操作,已经介绍了不少,字啊我们学习过程中也很频繁的去接触它,那么先来看内容吧。

QT通过三种形式提供了对线程的支持。它们分别是,一、平台无关的线程类,二、线程安全的事件投递,三、跨线程的信号-槽连接。这使得开发轻巧的多线程Qt程序更为容易,并能充分利用多处理器机器的优势。多线程编程也是一个有用的模式,它用于解决执行较长时间的操作而不至于用户界面失去响应。在Qt的早期版本中,在构建库时有不选择线程支持的选项,从4.0开始,线程总是有效的。

线程类

Qt 包含下面一些线程相关的类:

QThread 提供了开始一个新线程的方法

QThreadStorage 提供逐线程数据存储

QMutex 提供相互排斥的锁,或互斥量

QMutexLocker 是一个便利类,它可以自动对QMutex加锁与解锁

QReadWriterLock 提供了一个可以同时读操作的锁

QReadLocker与QWriteLocker 是便利类,它自动对QReadWriteLock加锁与解锁

QSemaphore 提供了一个整型信号量,是互斥量的泛化

QWaitCondition 提供了一种方法,使得线程可以在被另外线程唤醒之前一直休眠。

创建一个线程

为创建一个线程,子类化QThread并且重写它的run()函数,例如:

  1. class MyThread : public QThread{  
  2.      Q_OBJECTprotected:     void run();};  
  3. void MyThread::run(){...}  

之后,创建这个线程对象的实例,调用QThread::start()。于是,在run()里出现的代码将会在另外线程中被执行。

注意:QCoreApplication::exec()必须总是在主线程(执行main()的那个线程)中被调用,不能从一个QThread中调用。在GUI程序中,主线程也被称为GUI线程,因为它是***一个允许执行GUI相关操作的线程。另外,你必须在创建一个QThread之前创建QApplication(or QCoreApplication)对象。
 
线程同步

QMutex, QReadWriteLock, QSemaphore, QWaitCondition 提供了线程同步的手段。使用线程的主要想法是希望它们可以尽可能并发执行,而一些关键点上线程之间需要停止或等待。例如,假如两个线程试图同时访问同一个全局变量,结果可能不如所愿。

QMutex 提供相互排斥的锁,或互斥量。在一个时刻至多一个线程拥有mutex,假如一个线程试图访问已经被锁定的mutex,那么它将休眠,直到拥有mutex的线程对此mutex解锁。Mutexes常用来保护共享数据访问。
QReadWriterLock 与QMutex相似,除了它对 "read","write"访问进行区别对待。它使得多个读者可以共时访问数据。使用QReadWriteLock而不是QMutex,可以使得多线程程序更具有并发性。

  1. QReadWriteLock lock;void ReaderThread::run(){    // ...     lock.lockForRead();  
  2.      read_file();  
  3.      lock.unlock();     //...}void WriterThread::run(){ // ...  
  4.      lock.lockForWrite();  
  5.     write_file();  
  6.      lock.unlock();    // ...  

QSemaphore 是QMutex的一般化,它可以保护一定数量的相同资源,与此相对,一个mutex只保护一个资源。下面例子中,使用QSemaphore来控制对环状缓冲的访问,此缓冲区被生产者线程和消费者线程共享。生产者不断向缓冲写入数据直到缓冲末端,再从头开始。消费者从缓冲不断读取数据。信号量比互斥量有更好的并发性,假如我们用互斥量来控制对缓冲的访问,那么生产者,消费者不能同时访问缓冲。然而,我们知道在同一时刻,不同线程访问缓冲的不同部分并没有什么危害。

  1. const int DataSize = 100000;  
  2. const int BufferSize = 8192;  
  3. char buffer[BufferSize];  
  4. QSemaphore freeBytes(BufferSize);  
  5. QSemaphore usedBytes;  
  6. class Producer : public QThread{public:     void run();  
  7. };  
  8. void Producer::run(){  
  9.      qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));  
  10.      for (int i = 0; i < DataSize; ++i) {  
  11.          freeBytes.acquire();  
  12.          buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];  
  13.          usedBytes.release();  
  14.      }  
  15. }  
  16. class Consumer : public QThread{public:     void run();  
  17. };  
  18. void Consumer::run(){  
  19.      for (int i = 0;  
  20.  i < DataSize; ++i) {  
  21.          usedBytes.acquire();  
  22.          fprintf(stderr, "%c", buffer[i % BufferSize]);  
  23.          freeBytes.release();  
  24.      }  
  25.      fprintf(stderr, "\n");  
  26. }  
  27. int main(int argc, char *argv[]){  
  28.      QCoreApplication app(argc, argv);  
  29.      Producer producer;  
  30.      Consumer consumer;  
  31.      producer.start();  
  32.      consumer.start();  
  33.      producer.wait();  
  34.      consumer.wait();  
  35.      return 0;} 

QWaitCondition 允许线程在某些情况发生时唤醒另外的线程。一个或多个线程可以阻塞等待一QWaitCondition ,用wakeOne()或wakeAll()设置一个条件。wakeOne()随机唤醒一个,wakeAll()唤醒所有。

下面的例子中,生产者首先必须检查缓冲是否已满(numUsedBytes==BufferSize),如果是,线程停下来等待bufferNotFull条件。如果不是,在缓冲中生产数据,增加numUsedBytes,激活条件 bufferNotEmpty。使用mutex来保护对numUsedBytes的访问。另外,QWaitCondition::wait()接收一个mutex作为参数,这个mutex应该被调用线程初始化为锁定状态。在线程进入休眠状态之前,mutex会被解锁。而当线程被唤醒时,mutex会处于锁定状态,而且,从锁定状态到等待状态的转换是原子操作,这阻止了竞争条件的产生。当程序开始运行时,只有生产者可以工作。消费者被阻塞等待bufferNotEmpty条件,一旦生产者在缓冲中放入一个字节,bufferNotEmpty条件被激发,消费者线程于是被唤醒。

  1. const int DataSize = 100000;  
  2. const int BufferSize = 8192;  
  3. char buffer[BufferSize];  
  4. QWaitCondition bufferNotEmpty;  
  5. QWaitCondition bufferNotFull;  
  6. QMutex mutex;  
  7. int numUsedBytes = 0;  
  8. class Producer : public QThread{public:     void run();  
  9. };void Producer::run(){  
  10.      qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));  
  11.      for (int i = 0; i < DataSize; ++i) {  
  12.          mutex.lock();  
  13.          if (numUsedBytes == BufferSize)             bufferNotFull.wait(&mutex);  
  14.          mutex.unlock();   
  15.         buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];  
  16.          mutex.lock();  
  17.          ++numUsedBytes;  
  18.          bufferNotEmpty.wakeAll();  
  19.          mutex.unlock();  
  20.      }  
  21. }class Consumer : public QThread{public:     void run();  
  22. };void Consumer::run(){  
  23.      for (int i = 0; i < DataSize; ++i) {  
  24.          mutex.lock();  
  25.          if (numUsedBytes == 0)             bufferNotEmpty.wait(&mutex);  
  26.          mutex.unlock();  
  27.          fprintf(stderr, "%c", buffer[i % BufferSize]);  
  28.          mutex.lock();  
  29.          --numUsedBytes;   
  30.         bufferNotFull.wakeAll();  
  31.          mutex.unlock();  
  32.      }   
  33.     fprintf(stderr, "\n");  
  34. }int main(int argc, char *argv[]){  
  35.      QCoreApplication app(argc, argv);  
  36.      Producer producer;  
  37.      Consumer consumer;  
  38.      producer.start();   
  39.     consumer.start();   
  40.     producer.wait();  
  41.      consumer.wait();  
  42.      return 0;  

小结:QT 多线程程序详细设计 的内容介绍完了,想要了解耕读内容,请参考 解析 QT 多线程程序之可重入与线程安全 中篇,希望本文读你有帮助!

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...