zoukankan      html  css  js  c++  java
  • QWaitCondition(和Java的Notify机制非常相像)

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

    线程类

    Qt 包含下面一些线程相关的类:
    QThread 提供了开始一个新线程的方法
    QThreadStorage 提供逐线程数据存储
    QMutex  提供相互排斥的锁,或互斥量
    QMutexLocker 是一个便利类,它可以自动对QMutex加锁与解锁
    QReadWriterLock 提供了一个可以同时读操作的锁
    QReadLocker与QWriteLocker 是便利类,它自动对QReadWriteLock加锁与解锁
    QSemaphore 提供了一个整型信号量,是互斥量的泛化
    QWaitCondition 提供了一种方法,使得线程可以在被另外线程唤醒之前一直休眠。

    创建一个线程

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

     protected:
         void run();
     };

     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,可以使得多线程程序更具有并发性。

     QReadWriteLock lock;
     void ReaderThread::run()
     {
        // ...
         lock.lockForRead();
         read_file();
         lock.unlock();
         //...
     }

     void WriterThread::run()
     {
        // ...
         lock.lockForWrite();
         write_file();
         lock.unlock();
        // ...
     }

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

     const int DataSize = 100000;
     const int BufferSize = 8192;
     char buffer[BufferSize];

     QSemaphore freeBytes(BufferSize);
     QSemaphore usedBytes;

     class Producer : public QThread
     {
     public:
         void run();
     };

     void Producer::run()
     {
         qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
         for (int i = 0; i < DataSize; ++i) {
             freeBytes.acquire();
             buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];
             usedBytes.release();
         }
     }

     class Consumer : public QThread
     {
     public:
         void run();
     };

     void Consumer::run()
     {
         for (int i = 0; i < DataSize; ++i) {
             usedBytes.acquire();
             fprintf(stderr, "%c", buffer[i % BufferSize]);
             freeBytes.release();
         }
         fprintf(stderr, " ");
     }

     int main(int argc, char *argv[])
     {
         QCoreApplication app(argc, argv);
         Producer producer;
         Consumer consumer;
         producer.start();
         consumer.start();
         producer.wait();
         consumer.wait();
         return 0;
     }
    QWaitCondition 允许线程在某些情况发生时唤醒另外的线程。一个或多个线程可以阻塞等待一QWaitCondition ,用wakeOne()或wakeAll()设置一个条件。wakeOne()随机唤醒一个,wakeAll()唤醒所有。

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

     const int DataSize = 100000;
     const int BufferSize = 8192;
     char buffer[BufferSize];

     QWaitCondition bufferNotEmpty;
     QWaitCondition bufferNotFull;
     QMutex mutex;
     int numUsedBytes = 0;

     class Producer : public QThread
     {
     public:
         void run();
     };

     void Producer::run()
     {
         qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));

         for (int i = 0; i < DataSize; ++i) {
             mutex.lock();
             if (numUsedBytes == BufferSize)
                 bufferNotFull.wait(&mutex);
             mutex.unlock();

             buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];

             mutex.lock();
             ++numUsedBytes;
             bufferNotEmpty.wakeAll();
             mutex.unlock();
         }
     }

     class Consumer : public QThread
     {
     public:
         void run();
     };

     void Consumer::run()
     {
         for (int i = 0; i < DataSize; ++i) {
             mutex.lock();
             if (numUsedBytes == 0)
                 bufferNotEmpty.wait(&mutex);
             mutex.unlock();

             fprintf(stderr, "%c", buffer[i % BufferSize]);

             mutex.lock();
             --numUsedBytes;
             bufferNotFull.wakeAll();
             mutex.unlock();
         }
         fprintf(stderr, " ");
     }

     int main(int argc, char *argv[])
     {
         QCoreApplication app(argc, argv);
         Producer producer;
         Consumer consumer;
         producer.start();
         consumer.start();
         producer.wait();
         consumer.wait();
         return 0;
     }

    http://www.cppblog.com/yuanyajie/archive/2007/08/22/30599.html

  • 相关阅读:
    基于Python的人脸动漫转换
    let 与 var的区别
    【LeetCode】汇总
    【HDU】4632 Palindrome subsequence(回文子串的个数)
    【算法】均匀的生成圆内的随机点
    【LeetCode】725. Split Linked List in Parts
    【LeetCode】445. Add Two Numbers II
    【LeetCode】437. Path Sum III
    【LeetCode】222. Count Complete Tree Nodes
    【LeetCode】124. Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/findumars/p/5804627.html
Copyright © 2011-2022 走看看