C++线程交叉打印1-100

哈哈哈,睡醒了突然觉得昨晚的太简单了,又想起了一道题,交叉打印1-100,虽然难度也还是只提升了一丢丢。但是,复习一下也算嘛。

#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>

using namespace std;

mutex data_mutex;
condition_variable flag_cond;
bool flag = true;


void printji()
{
	int i = 1;
	while (i <= 100)
	{
		//this_thread::sleep_for(chrono::seconds(1));
		unique_lock<mutex> lck(data_mutex);
		flag_cond.wait(lck, [] {return flag; });
		cout << "A " << i << endl;
		i += 2;
		flag = false;
		flag_cond.notify_one();
	}
}
void printou()
{
	int i = 2;
	while (i <= 100)
	{
		unique_lock<mutex> lck(data_mutex);
		flag_cond.wait(lck, [] {return !flag; });
		cout << "B " << i << endl;
		i += 2;
		flag = true;
		flag_cond.notify_one();
	}
}

int main()
{
	thread t1(printji);
	thread t2(printou);
	t1.join();
	t2.join();
	return 0;
}

这里虽然简单,但还是说一句,开始的时候我把i是i+1,犯了低级错误,两个函数中的i其实不是一个i,验证一下,把第二个里面换成j,其实并没有变化,所以两个线程交叉打印自己拥有的一个数,交互的只有flag。
我想让他们改的是同一个数,交叉修改此数。
我们先测试一下异步的吧,不加锁修改一个变量看会发生什么?

#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>

using namespace std;

mutex data_mutex;
condition_variable flag_cond;
bool flag = true;
int i = 1;

void printji()
{
	while (i <= 100)
	{
		cout << "A" << i++ << endl;
	}
	/*while (i <= 100)
	{
		//this_thread::sleep_for(chrono::seconds(1));
		unique_lock<mutex> lck(data_mutex);
		flag_cond.wait(lck, [] {return flag; });
		cout << "A " << i << endl;
		i += 2;
		flag = false;
		flag_cond.notify_one();
	}*/
}
void printou()
{
	while (i <= 100)
	{
		cout << "B" << i++ << endl;
	}
	/*int j = 2;
	while (j <= 100)
	{
		unique_lock<mutex> lck(data_mutex);
		flag_cond.wait(lck, [] {return !flag; });
		cout << "B " << j << endl;
		j += 2;
		flag = true;
		flag_cond.notify_one();
	}*/
}

int main()
{
	thread t1(printji);
	thread t2(printou);
	t1.join();
	t2.join();
	return 0;
}

在这里插入图片描述在这里插入图片描述
从图中可以看出,线程抢占式修改,每次执行都不一样。
所以我们还是同步一下,加条件变量修改同一个数。

#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>

using namespace std;

mutex data_mutex;
condition_variable flag_cond;
bool flag = true;
int i = 1;

void printji()
{
	while (i < 100)//i这里有改动,去掉等于
	{
		//this_thread::sleep_for(chrono::seconds(1));
		unique_lock<mutex> lck(data_mutex);
		flag_cond.wait(lck, [] {return flag; });
		cout << "A " << i << endl;
		i += 1;//此处变为+1
		flag = false;
		flag_cond.notify_one();
	}
}
void printou()
{
	while (i < 100)
	{
		unique_lock<mutex> lck(data_mutex);
		flag_cond.wait(lck, [] {return !flag; });
		cout << "B " << i << endl;
		i += 1;
		flag = true;
		flag_cond.notify_one();
	}
}

int main()
{
	thread t1(printji);
	thread t2(printou);
	t1.join();
	t2.join();
	return 0;
}

原本我以为挺简单的一个题,但还是栽了跟头,开始的时候我还是以i<=100来作为循环条件,后来发现会打印到101,也就是最后A线程会打印101。改成小于后就好了。
如果你有幸看到了,给点思考时间。

思考已过。我百思不得其解,而后想通了。在进入while循环后,并不会直接进行到下一次,而是在条件变量处等待。举个例子。B在将i修改为98后,通知条件变量处等待的线程。此时A处是在上一次打印完97,加1后重新进入循环阻塞在条件变量,也就是进入循环时以98进入,但阻塞时,B线程将i+1,所以打印出来就是99,然后加1,为100后,此时A线程打印完99后退出循环。B此时等待条件变量,在A加到100后,先打印,然后+1,退出循环。所以最后i是以101结束的。
验证很简单。我们在线程回收后,main函数打印一下i的值。
然后结果如下。
在这里插入图片描述
会发现,一个你想当然的事情在做的时候并没有那么简单,简单的题好好挖一下就能深刻的理解概念。此处就理解了条件变量。
哈哈哈哈,第一次这么有条不紊的分析加验证还是很开心的。虽然比较简单但是,一步步来。

发布了22 篇原创文章 · 获赞 0 · 访问量 354

猜你喜欢

转载自blog.csdn.net/yanchenzhi/article/details/105064740
今日推荐