QWaitCondition提供了另一种改进的线程同步方法,与QMutex结合,可以使一个线程在满足一定条件下时通知其他多
个线程,使它们及时做出相应,相对于互斥量效率高一点。
QWaitCondition提供如下函数:
wait(QMutex* lockedmutex):解锁互斥量lockedmutex,并阻塞等待唤醒,被唤醒后锁定lockedmutex并退出函数
wakeAll():唤醒所有处于等待状态的线程,唤醒顺序不确定,由操作系统调度策略决定
wakeOne(): 唤醒一个处于等待状态的线程,不确定唤醒哪一个,由操作系统调度策略决定
以下是根据QWaitCondition “生产者-消费者”模式改进的投掷骰子的程序:
QMutex mutex;
QWaitCondition diceValueAvailabel;
int seq = 0;
int diceValue = 0;
QThreadProducer::QThreadProducer(QObject* parent)
: QThread(parent)
{
m_gonOn = false;
}
QThreadProducer::~QThreadProducer() {
}
void QThreadProducer::stopThread() {
m_gonOn = false;
}
void QThreadProducer::run() {
m_gonOn = true;
seq = 0;
qsrand(QTime::currentTime().msec());
while (m_gonOn) {
mutex.lock();
diceValue = (qrand() % 6) + 1;
seq++;
qDebug() << "QThreadProducer seq: " << seq << " diceValue: " << diceValue;
mutex.unlock();
diceValueAvailabel.wakeAll();
msleep(500);
}
}
QThreadConsumer::QThreadConsumer(QObject* parent)
: QThread(parent)
{
m_gonOn = false;
}
QThreadConsumer::~QThreadConsumer() {
}
void QThreadConsumer::stopThread() {
m_gonOn = false;
}
void QThreadConsumer::run() {
m_gonOn = true;
while (m_gonOn) {
mutex.lock();
diceValueAvailabel.wait(&mutex);
qDebug() << "returnDiceValueSignal seq: " << seq << " diceValue: " << diceValue;
emit returnDiceValueSignal(seq, diceValue);
mutex.unlock();
}
}
主线程调用代码为:
void QthreadProject::on_startThreadBtn_clicked() {
if (!m_consumer->isRunning())
m_consumer->start();
if (!m_producer->isRunning())
m_producer->start();
ui.startThreadBtn->setEnabled(false);
ui.stopThreadBtn->setEnabled(true);
}
void QthreadProject::on_stopThreadBtn_clicked() {
if (m_producer->isRunning()) {
m_producer->stopThread();
m_producer->quit();
m_producer->wait();
}
if (m_consumer->isRunning()) {
m_consumer->stopThread();
m_consumer->terminate();//必须用terminate()终结线程,因为consumer线程可能还处于条件等待的
阻塞状态中,无法正常结束
m_consumer->wait();
}
ui.startThreadBtn->setEnabled(true);
ui.stopThreadBtn->setEnabled(false);
}
void QthreadProject::on_clearBtn_clicked() {
ui.plainTextEdit->clear();
}
void QthreadProject::returnDiceValueSlot(int seq, int dicevalue) {
QString str = QString::asprintf("第%d次投掷骰子,点数为%d", seq, dicevalue);
ui.plainTextEdit->appendPlainText(str);
QPixmap pix;
QString filename = QString::asprintf("icon/%d.png", dicevalue);
pix.load(filename);
ui.label->setPixmap(pix);
ui.label->setScaledContents(true);
}