背景
項目中用到多線程,對線程的執行順序有要求:
A.一個線程先收數據
B.一個線程處理數據
C.一個線程再將處理后的數據發送出去
要求三個線程按照ABC的順序循環執行。
思路
子類化多線程方法
重寫子類的run函數,在run函數內用while(1)來常駐線程,循環體內通過檢查全局變量來判斷是否到自己執行,不是自己線程則跳過,是自己線程執行完后改變全局標志位。通過全局標志位來控制線程的執行順序。所以需要一個全局變量來標記當前應當執行的線程,同時用一個互斥量來保護該全局變量。
movetoThread多線程方法
為每個線程設計相應的方法類,將生成的方法類對象移入到對應的線程內,方法類的方法必須通過信號和槽的方式來觸發。
本文采用第二種思路來實現線程的順序執行
QWaitConditon簡介
線程如何睡眠?
調用QWaitCondition的wait函數將使得調用它的線程進入睡眠狀態
線程如何醒來?
在另外的線程中調用QWaitConditon的wakeOne或者wakeAll方法將喚醒等待它的線程
實現過程
先定義全局變量
QWaitCondition condition_input; //數據收線程的條件變量,控制線程睡眠和喚醒
QWaitCondition condition_process;//數據處理線程的條件變量,控制線程睡眠和喚醒
QWaitCondition condition_output;//數據發線程的條件變量,控制線程睡眠和喚醒
//保護條件變量,防止多線程同時訪問條件變量
QMutex mutex_input;
QMutex mutex_process;
QMutex mutex_output;
1
2
3
4
5
6
7
8
2.實現接收數據的方法的槽函數
void input::work()
{
while(1)//使得線程常駐
{
qDebug()<<"input1";
mutex_process.lock();
condition_process.wakeOne();//喚醒下一次的數據處理線程
mutex_process.unlock();
mutex_input.lock();
condition_input.wait(&mutex_input);//睡眠當前的收線程
mutex_input.unlock();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
3.實現處理數據的方法的槽函數
void process::work()
{
while (1)
{
qDebug()<<"process2";
mutex_output.lock();
condition_output.wakeOne();//喚醒下一次的發線程
mutex_output.unlock();
mutex_process.lock();
condition_process.wait(&mutex_process);//睡眠當前處理線程
mutex_process.unlock();
}
}
void process::threadSleep()
{
qDebug()<<QThread::currentThreadId();
mutex_process.lock();
condition_process.wait(&mutex_process);//睡眠當前處理線程
mutex_process.unlock();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
4.實現發送數據的方法的槽函數
void output::work()
{
while (1)
{
qDebug()<<"output3";
mutex_input.lock();
condition_input.wakeOne();//喚醒下一次的收線程
mutex_input.unlock();
mutex_output.lock();
condition_output.wait(&mutex_output);//睡眠當前的發線程
mutex_output.unlock();
}
}
void output::threadSleep()
{
qDebug()<<QThread::currentThreadId();
mutex_output.lock();
condition_output.wait(&mutex_output);//睡眠當前的發線程
mutex_output.unlock();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
5.main函數中的最終實現
input_thread = new inputThread();
process_thread = new processThread();
out_thread = new outputThread();
//開啟線程
input_thread ->start();
process_thread ->start();
out_thread ->start();
//生成方法對象
data_input = new input();
data_process = new process();
data_output = new output();
//移入線程
data_input->moveToThread(input_thread);
data_process->moveToThread(process_thread);
data_output->moveToThread(out_thread);
//使得數據處理和數據發送線程睡眠的槽函數和按鍵1的點擊信號關聯
connect(this,SIGNAL(click1()),data_process,SLOT(threadSleep()));
connect(this,SIGNAL(click1()),data_output,SLOT(threadSleep()));
//使得三個線程的work槽函數和按鍵1的點擊信號關聯
connect(this,SIGNAL(click2()),data_input,SLOT(work()));
connect(this,SIGNAL(click2()),data_process,SLOT(work()));
connect(this,SIGNAL(click2()),data_output,SLOT(work()));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
使用方法
先觸發click1信號,使得數據處理線程和數據發送線程睡眠;再觸發click2信號,使得三個線程按照既定的順序ABC循環執行。
輸出結果
input1
process2
output3
input1
process2
output3
input1
process2
output3
input1
process2
output3
1
2
3
4
5
6
7
8
9
10
11
12
注意事項
線程類的run函數里記得加exec(),使得線程常駐
---------------------
作者:蝸牛在聽雨
來源:CSDN
原文:https://blog.csdn.net/omg_orange/article/details/82388243
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!