哈哈哈,睡醒了突然觉得昨晚的太简单了,又想起了一道题,交叉打印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的值。
然后结果如下。
会发现,一个你想当然的事情在做的时候并没有那么简单,简单的题好好挖一下就能深刻的理解概念。此处就理解了条件变量。
哈哈哈哈,第一次这么有条不紊的分析加验证还是很开心的。虽然比较简单但是,一步步来。