http://blog.csdn.net/mznewfacer/article/details/6965799
QMutex类
一个线程可以锁定互斥量,并且在它锁定之后,其它线程就不能再锁定这个互斥量了,试图这样做的线程都会被阻塞直到互斥量被释放
class MyClass { public: void doStuff( int ); private: QMutex mutex; int a; int b; }; // 这里设置a为c,b为c*2。 void MyClass::doStuff( int c ) { mutex.lock(); a = c; b = c * 2; mutex.unlock(); }
QWaitCondition
线程等待的条件QWaitCondition指出发生了什么事情,阻塞将一直持续到这种事情发生。当某种事情发生了,QWaitCondition可以唤醒等待这一事件的线程之一或全部
#include <qapplication.h> #include <qpushbutton.h> // 全局条件变量 QWaitCondition mycond; // Worker类实现 class Worker : public QPushButton, public QThread { Q_OBJECT public: Worker(QWidget *parent = 0, const char *name = 0) : QPushButton(parent, name) { setText("Start Working"); // 连接从QPushButton继承来的信号和我们的slotClicked()方法 connect(this, SIGNAL(clicked()), SLOT(slotClicked())); // 调用从QThread继承来的start()方法……这将立即开始线程的执行 QThread::start(); } public slots: void slotClicked() { // 唤醒等待这个条件变量的一个线程 mycond.wakeOne(); } protected: void run() { // 这个方法将被新创建的线程调用…… while ( TRUE ) { // 锁定应用程序互斥锁,并且设置窗口标题来表明我们正在等待开始工作 qApp->lock(); setCaption( "Waiting" ); qApp->unlock(); // 等待直到我们被告知可以继续 mycond.wait(); // 如果我们到了这里,我们已经被另一个线程唤醒……让我们来设置标题来表明我们正在工作 qApp->lock(); setCaption( "Working!" ); qApp->unlock(); // 这可能会占用一些时间,几秒、几分钟或者几小时等等,因为这个一个和GUI线程分开的线程,在处理事件时,GUI线程不会停下来…… do_complicated_thing(); } } }; // 主线程——所有的GUI事件都由这个线程处理。 int main( int argc, char **argv ) { QApplication app( argc, argv ); // 创建一个worker……当我们这样做的时候,这个worker将在一个线程中运行 Worker firstworker( 0, "worker" ); app.setMainWidget( &worker ); worker.show(); return app.exec(); }
只要你按下按钮,这个程序就会唤醒worker线程,这个线程将会进行并且做一些工作并且然后会回来继续等待被告知做更多的工作。如果当按钮被按下时,worker线程正在工作,那么就什么也不会发生。当线程完成了工作并且再次调用QWaitCondition::wait(),然后它就会被开始。
QWaitCondition
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; }