Say nothing, but first look at the results of the operation:
Examples of this program are listed in the links below, which should be appreciated and followed.
Program Connection Extraction Code: t7yh
QWaitCondition provides the following functions:
- Wait (QMutex *lockedM utex), unlocks the mutex lockedM utex, blocks the wait wake condition, lockedM utex is locked after waking up and exits the function
- wakeAll(), wakes all waiting threads in an indeterminate order, determined by the scheduling policy of the operating system
- wakeOne(), wakes a thread in a waiting state, which thread is not sure which to wake, depending on the scheduling policy of the operating system
QWaitCondition s are generally used in producer/consumer models.Producer produces data, Consumer uses data, and the three-threaded example of data collection, display, and storage described above applies to this model.
First, let's build two classes, which are in qmythread.h
#ifndef QMYTHREAD_H #define QMYTHREAD_H //#include <QObject> #include <QThread> class QThreadProducer : public QThread { Q_OBJECT private: bool m_stop=false; //Stop Thread protected: void run() Q_DECL_OVERRIDE; public: QThreadProducer(); void stopThread(); }; class QThreadConsumer : public QThread { Q_OBJECT private: bool m_stop=false; //Stop Thread protected: void run() Q_DECL_OVERRIDE; public: QThreadConsumer(); void stopThread(); signals: void newValue(int seq,int diceValue); }; #endif // QMYTHREAD_H
Corresponding cpp
#include "qmythread.h" #include <QWaitCondition> #include <QTime> #include <QMutex> static QMutex mutex; static QWaitCondition newdataAvailable; static int seq=0;//Sequence Number static int diceValue; QThreadProducer::QThreadProducer() { } void QThreadProducer::stopThread() { QMutexLocker locker(&mutex); m_stop=true; } void QThreadProducer::run() { m_stop=false;//Thread start time m_stop=false seq=0; qsrand(QTime::currentTime().msec());//Random number initialization, qsrand is thread safe while(!m_stop)//Cycle body { mutex.lock(); diceValue=qrand(); //Get Random Numbers diceValue=(diceValue % 6)+1; seq++; mutex.unlock(); newdataAvailable.wakeAll();//Wake up all threads with new data msleep(500); //Thread sleeps 100ms } } void QThreadConsumer::run() { m_stop=false;//Thread start time m_stop=false while(!m_stop)//Cycle body { mutex.lock(); newdataAvailable.wait(&mutex);//mutex is unlocked so that other threads can use it emit newValue(seq,diceValue); mutex.unlock(); // msleep(100); //Thread sleeps 100ms } } QThreadConsumer::QThreadConsumer() { } void QThreadConsumer::stopThread() { QMutexLocker locker(&mutex); m_stop=true; }
ps: If you don't know QThread, QMutex, you can look at the relevant information, or pay attention to me, see the usage I wrote earlier.
QThreadConsumer reads the number of dice rolls and the number of points, and wells transmit the data by sending a signal.
Variables for the number of dice rolls and the number of points are defined as shared variables so that both threads can access, and the QThreadProducer::run() function is responsible for generating data every 500 milliseconds by throwing a dummy. By waking up all waiting threads using the newdataAvailable.wakeAll() condition, the QThreadConsumer::while loop in the run() function,First you need to lock the mutex to execute:
newdataAvailable.wait ( &mutex);
This statement takes mutex as an input parameter and unlocks mutex internally so that other threads can use mutex, newdataAvailable, to a wait state.When the QThreadProducer generates new data and wakes all threads with newdataAvailable.wakeAll(), newdataAvailable.wait (&mutex) locks mutex again and exits the blocking state to execute the following statement.
Following is the page code:
#ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include <QTimer> #include "qmythread.h" namespace Ui { class Dialog; } class Dialog : public QDialog { Q_OBJECT private: QThreadProducer threadProducer; QThreadConsumer threadConsumer; protected: void closeEvent(QCloseEvent *event); public: explicit Dialog(QWidget *parent = 0); ~Dialog(); private slots: void onthreadA_started(); void onthreadA_finished(); void onthreadB_started(); void onthreadB_finished(); void onthreadB_newValue(int seq, int diceValue); void on_btnClear_clicked(); void on_btnStopThread_clicked(); void on_btnStartThread_clicked(); private: Ui::Dialog *ui; }; #endif // DIALOG_H
#include "dialog.h" #include "ui_dialog.h" void Dialog::closeEvent(QCloseEvent *event) {//close window if (threadProducer.isRunning()) { threadProducer.stopThread(); threadProducer.wait(); } if (threadConsumer.isRunning()) { threadConsumer.terminate(); //Force end with terminate because threadB may be in a waiting state threadConsumer.wait();// } event->accept(); } Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) { ui->setupUi(this); connect(&threadProducer,SIGNAL(started()),this,SLOT(onthreadA_started())); connect(&threadProducer,SIGNAL(finished()),this,SLOT(onthreadA_finished())); connect(&threadConsumer,SIGNAL(started()),this,SLOT(onthreadB_started())); connect(&threadConsumer,SIGNAL(finished()),this,SLOT(onthreadB_finished())); connect(&threadConsumer,SIGNAL(newValue(int,int)),this,SLOT(onthreadB_newValue(int,int))); } Dialog::~Dialog() { delete ui; } void Dialog::onthreadA_started() { ui->LabA->setText("Thread Producer state: started"); } void Dialog::onthreadA_finished() { ui->LabA->setText("Thread Producer state: finished"); } void Dialog::onthreadB_started() { ui->LabB->setText("Thread Consumer state: started"); } void Dialog::onthreadB_finished() { ui->LabB->setText("Thread Consumer state: finished"); } void Dialog::onthreadB_newValue(int seq,int diceValue) { QString str=QString::asprintf("No. %d Dice roll twice with:%d", seq,diceValue); ui->plainTextEdit->appendPlainText(str); QPixmap pic; QString filename=QString::asprintf(":/dice/images/d%d.jpg",diceValue); pic.load(filename); ui->LabPic->setPixmap(pic); } void Dialog::on_btnClear_clicked() { ui->plainTextEdit->clear(); } void Dialog::on_btnStopThread_clicked() {//End Thread threadProducer.stopThread();//End thread run() function execution threadProducer.wait();// // threadConsumer.stopThread();//end thread run() function execution threadConsumer.terminate(); //Force end with terminate because threadB may be in a waiting state threadConsumer.wait();// ui->btnStartThread->setEnabled(true); ui->btnStopThread->setEnabled(false); } void Dialog::on_btnStartThread_clicked() {//Start Thread threadConsumer.start(); threadProducer.start(); ui->btnStartThread->setEnabled(false); ui->btnStopThread->setEnabled(true); }
One thing to note here is:
The order in which the two threads are started should not be swapped. Start threadConsumer first to make it wait, then start threadProducer, so that threadConsumer can respond in time when wakeAll() is in threadProducer, or it will lose the data of the first time a false throw is made.
When terminating a thread, if the threadProducer thread is terminated first in the order above, terminate () must be used to force the end of the threadConsurner thread because the threadConsumer may still be blocked by a conditional wait and will not be able to terminate the thread properly.
Please give some compliment to those who like this article and let's work together.