Qt之多線程(三)

一、多線程

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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章