Qt 控制线程的顺序执行(使用QWaitCondition,并且线程类的run函数里记得加exec(),使得线程常驻)

背景
项目中用到多线程,对线程的执行顺序有要求:
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
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自www.cnblogs.com/findumars/p/10344546.html