目录
接着上一篇,本篇实现更复杂一些的条件变量的处理。
若对题目要求还不是很清楚的,可以通过这个链接查看前一篇内容:
<一>、C++实现多线程的同步处理:控制ABC的输出顺序,输出10组,mutex+condition_variable-优快云博客
场景:
这里面有个重要的概念是条件变量,顾名思义,需要加上条件来处理的场景就可以使用了,那么我们来研究以下需求的场景:
需要3条线程输出不同的字符,分别为A、B、C,并且顺序要固定住:ABCABC...ABC[共10组],这样的情况下,只需要有一个计数器来统计字符的输出数量,通过这个计数器来对3取余,通过余数来当条件控制输出顺序即可。
这个使用条件变量的方式,跟标志位有异曲同工之妙,并且不用来回变来变去的,只需要计数器不停递增即可。
废话不多说了,上代码:
核心代码:
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
//int g_flag = 0; // 全局标志位 0输出A,1输出B,2输出C
mutex g_mutex;
condition_variable g_conv; // 条件变量
int g_cnt = 0; // 计数器,初始化为0
void outA()
{
/*for (int i = 0; i < 10;) {
if (g_flag == 0) { // 标志位为0 输出 A
cout << "A"; // 输出目标字符A
++i; // 次数自增
//g_mutex.lock();
//unique_lock<mutex> ul(g_mutex); // 唯一锁,实例化时,自动加锁,离开作用域调析构自动解锁
lock_guard<mutex> lg(g_mutex); // 守卫锁,也能起到自动加锁,自动解锁的作用
g_flag = 1; // 修改标志位为1 让B输出
//g_mutex.unlock();
}
// 若if条件不成立,就会一直死循环
}*/
/ 以下为条件变量相关代码
for (int i = 0; i < 10; ++i) {
unique_lock<mutex> ul(g_mutex); // 先创建一把唯一锁
g_conv.wait(ul, [=] {return g_cnt % 3 == 0; }); // 条件变量等待的时候,当条件为真时 继续往下 余数为0继续,否则一直阻塞
cout << "A"; // 输出目标字符
++g_cnt; // 计数器递增
g_conv.notify_all(); // 唤醒所有
}
}
void outB()
{
/*for (int i = 0; i < 10;) {
if (g_flag == 1) { // 标志位为1 输出 B
cout << "B";
++i;
//g_mutex.lock();
//unique_lock<mutex> ul(g_mutex);
lock_guard<mutex> lg(g_mutex); // 守卫锁,也能起到自动加锁,自动解锁的作用
g_flag = 2; // 修改标志位为2 接着让C输出
//g_mutex.unlock();
}
}*/
/ 以下为条件变量相关代码
for (int i = 0; i < 10; ++i) {
unique_lock<mutex> ul(g_mutex);
g_conv.wait(ul, [=] {return g_cnt % 3 == 1; });
cout << "B";
++g_cnt;
g_conv.notify_all();
}
}
void outC()
{
/*for (int i = 0; i < 10;) {
if (g_flag == 2) { // 标志位为2 输出 C
cout << "C";
++i;
//g_mutex.lock();
//unique_lock<mutex> ul(g_mutex);
lock_guard<mutex> lg(g_mutex); // 守卫锁,也能起到自动加锁,自动解锁的作用
g_flag = 0; // 修改标志位为0,让A输出
//g_mutex.unlock();
}
}*/
/ 以下为条件变量相关代码
for (int i = 0; i < 10; ++i) {
unique_lock<mutex> ul(g_mutex);
g_conv.wait(ul, [=] {return g_cnt % 3 == 2; });
cout << "C";
++g_cnt;
g_conv.notify_all();
}
}
int main()
{
thread tA(&outA); // A的线程
tA.detach();
thread tB(&outB); // B的线程
tB.detach();
thread tC(&outC); // C的线程
tC.join(); // 最后一条线程需要用join来阻塞,防止主函数立即结束
return 0;
}
输出效果:
和之前没啥区别,不过效果更好控制,逻辑更简单易控。
优化后的代码,也可以查看这个帖子:
<三>、代码优化:C++实现多线程的同步处理:控制ABC的输出顺序,输出10组,mutex+condition_variable-优快云博客