一、多線程
QWaitCondition類
1.1 QWaitCondition類的使用
案例:----書店管理員給貨架上放書,學生來買書,二者同時進行
思路:
1、讓書店管理員連續放100本書,但書架上只能容下20本書,因此,當書架放滿
書後,書店管理員必須等待,等待學生(購書者)買走1本或多本書
2、學生,即購書者連續買10本書,但書架上沒有書時,學生必須等待,等待書
店管理員放1本或多本書到書架上
主界面的cpp文件:
#include "waitcondition001widget.h"
#include "ui_waitcondition001widget.h"
#include "adminthread.h"
#include "studentthread.h"
int numBook=0; //代表書架上有多少本書,初始時沒有書
QMutex mutex; //定義1個鎖,當書店管理員、學生 查詢和修改numBook時,
要先加鎖
QWaitCondition waitCondition; //這是等待條件類的對象,它一般要和QMutex聯合使
用;它可以解決 睡眠----喚醒 的問題
WaitCondition001Widget::WaitCondition001Widget(QWidget *parent)
: QWidget(parent), ui(new Ui::WaitCondition001Widget)
{
ui->setupUi(this);
}
WaitCondition001Widget::~WaitCondition001Widget()
{
delete ui;
}
void WaitCondition001Widget::on_pushButton_clicked()//主界面上,點
擊按鈕後,將調用該函數
{
StudentThread *studentThread=new StudentThread;//建立1個學生
類
AdminThread *adminThread=new AdminThread; //建立1個書店
管理員類
studentThread->start(); //將建立和運行1個子線程,模擬
學生連續買10本書的情況
adminThread->start(); //將建立和運行1個子線程,模擬
書店管理員連續在書架上放100本書的情況
}
//書店管理員的h文件
#include <QtCore>
class AdminThread : public QThread
{
public:
AdminThread();
void run();
};
//書店管理員的cpp文件
#include "adminthread.h"
extern int numBook;
extern QMutex mutex;
extern QWaitCondition waitCondition;
AdminThread::AdminThread()
{
}
void AdminThread::run()
{
for(int i=0;i<100;i++)
{
mutex.lock();
if(numBook==20) //條件成立時,說明書架上的書放滿了;當前線程應
該睡眠,把cpu交給其它線程運行;但睡眠前,應該先要解鎖
{
mutex.unlock(); //解鎖
waitCondition.wait(&mutex); //當前線程睡眠
continue;
}
else
{
qDebug()<<"書店管理員放好了1本書"+QString::number(i);
numBook++; //書架上多了1本書,所以要執行
該語句
waitCondition.wakeOne(); //書架上的書增加了,因此,可以喚醒其它
睡眠的線程了。----注意,是隨機喚醒了1個線程。
}
mutex.unlock(); //每循環1次,應解鎖1次;這樣別的線程得到時間片
後,也可以加解鎖了。
sleep(2); //本線程睡2秒,而且時間片還會切換到其
它線程
}
return;
}
//學生(購書者)的h文件
#include <QtCore>
class StudentThread : public QThread
{
public:
StudentThread();
void run();
};
//學生(購書者)的cpp文件
#include "studentthread.h"
extern int numBook;
extern QMutex mutex;
extern QWaitCondition waitCondition;
StudentThread::StudentThread()
{
}
void StudentThread::run()
{
for(int i=0;i<10;i++)
{
mutex.lock();
if(numBook==0)
{
mutex.unlock();
waitCondition.wait(&mutex);
continue;
}
else
{
qDebug()<<"學生拿到了1本書"+QString::number(i);
numBook--;
waitCondition.wakeOne();
}
mutex.unlock();
sleep(2);
}
return;
}
1.2 上述代碼的改進
上述代碼存在的問題:----以書店線程爲例
1、一旦if語句中的條件成立,則當前的i就不會被打印出來了,因爲會越過else
中的打印
原來的代碼:
void AdminThread::run()
{
for(int i=0;i<100;i++)
{
mutex.lock();
if(numBook==20) //條件成立時,說明書架上的書放滿了;當前線程應
該睡眠,把cpu交給其它線程運行;但睡眠前,應該先要解鎖
{
mutex.unlock(); //解鎖
waitCondition.wait(&mutex); //當前線程睡眠
continue;
}
else
{
qDebug()<<"書店管理員放好了1本書"+QString::number(i);
numBook++; //書架上多了1本書,所以要執行
該語句
waitCondition.wakeOne(); //書架上的書增加了,因此,可以喚醒其它
睡眠的線程了。----注意,是隨機喚醒了1個線程。
}
mutex.unlock(); //每循環1次,應解鎖1次;這樣別的線程得到時間片
後,也可以加解鎖了。
sleep(2); //本線程睡2秒,而且時間片還會切換到其
它線程
}
return;
}
改進後的代碼:
void AdminThread::run()
{
for(int i=0;i<100;i++)
{
mutex.lock();
while(numBook==20)
{
mutex.unlock();
waitCondition.wait(&mutex);
mutex.lock();
//continue;
}
qDebug()<<"書店管理員放好了1本書"+QString::number(i);
numBook++;
waitCondition.wakeOne();
mutex.unlock();
msleep(2);
}
return;
}
類似的,學生(購書者)的run函數也要改進爲:
void StudentThread::run()
{
for(int i=0;i<10;i++)
{
mutex.lock();
while(numBook==0)
{
mutex.unlock();
waitCondition.wait(&mutex);
mutex.lock();
//continue;
}
qDebug()<<"學生拿到了1本書"+QString::number(i);
numBook--;
waitCondition.wakeOne();
mutex.unlock();
msleep(2);
}
return;
}
1.3 上述代碼的另外1種用法:
void AdminThread::run()
{
for(int i=0;i<100;i++)
{
mutex.lock();
while(numBook==20)
{
//mutex.unlock(); //註釋掉該行
waitCondition.wait(&mutex);
//mutex.lock(); //註釋掉該行 能註釋
掉這2行的原因是:wait函數會在wait前自動unlock1次,wait後自動lock1次,因此可以
省這2行語句。
//continue; //但推薦不要省,這樣可
以增加代碼的可讀性,即wait前要unlock,否則別的線程得到時間片後,得不到鎖,還是
幹不了啥
}
qDebug()<<"書店管理員放好了1本書"+QString::number(i);
numBook++;
waitCondition.wakeOne();
mutex.unlock();
msleep(2);
}
return;
}
Qt之多線程(三)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.