下次学习内容再写博客
立个flag:从现在开始 每天学习的内容及时写博客记录,为了方便以后复习相关内容时有帮助。刚自学多线程编程,博客中难免有错误。如果有幸有大佬看到 还望指正。
初次使用mutex
c++11中新增了mutex,condition_variable库,里面有互斥锁,条件变量以及其他和多线程有关的函数。有待探索…
代码功能简介:开辟俩个线程,模拟生产者消费者模型,生产线程产生随机数据,插入到队列中。消费线程消耗数据,从队列中拿走数据。由于要对同一个队列操作,也就是多线程编程中的“临界区”操作,所以需要上锁,以避免出现各种奇怪的错误。 (有时候队列中一个数取出来俩次,有时候取出来一个没插进去的数。等)
先上代码
#include <thread>
#include <iostream>
#include <condition_variable>
#include <queue>
#include <random>
#include <Windows.h>
using namespace std;
mutex mut;
condition_variable cond;
queue<int> data_que;
int ProduceMount = 10;
mut 设置成全局变量,被俩个线程抢夺
cond是条件变量,是一种进阶使用,用于一个线程需要另一个线程完成任务后才能继续执行时使用。
这里有多种可以实现的方式
方式1 | 方式2 |
---|---|
mutex.lock();待执行代码;mutex.unlock(); | lock_guard lg(mut);待执行代码… |
由于方法一中如果待执行代码中出现return;或者异常,就会使得解锁代码没有被执行。此时就会导致死锁或者资源无法被再次获取。方法二采用一个叫lock_guard的模板锁,这种模板锁在构造函数调用的时候就会上锁,在对象被销毁时自动解锁。手动析构会出错。可以说更加智能,但是问题就是无法手动解锁有时候头疼。下面我想了一个解决方法
void Data_Produce_Thread()
{
int i = 0;
for (;i < ProduceMount;i++) //需要生产10个物品
{
int tmp = rand() % 20; //生产0~20的伪随机数
{
lock_guard<mutex> lg(mut);//构造,上锁
cout << "生产线程:生产" << tmp << endl;
data_que.push(tmp);
cond.notify_one();// 表示此线程插入一个数的任务已经完成了
}//**这个大括号 起了很重要的作用,我在这里思索了很多次解决办法**
//稍后说明作用
}
Sleep(200);
}
所谓大括号括起来的这部分 是一个叫代码块的东西,执行完的时候,内部申请的资源就会被释放。这里的作用就是在执行sleep(200)之前调用lg的析构函数,此时就会解锁。解锁的目的就是让消耗线程及时抢到锁的控制,让消耗线程消耗产生的数。
这里如果不用括号有个很大的问题,那就是for循环没有执行完,lg是不会被析构的,所以必须先sleep 后析构。 可是如果后析构,代码执行的结果就是,很快进入下次循环 lg又被构造 又抢到锁。 消耗线程根本来不及抢到锁的资源。 那么就会出现以下结果:
即使cond变量已经调用了notify_one函数 通知消耗线程 数据已经插好,但是消耗线程抢不到锁,所以只好等生产线程生产完才能执行。加入之后就可以达到预期效果,而且建议自己可以在消耗线程和生产线程修改sleep得时间,观察不同结果有助于理解多线程编程。 我也是新手 学习中…
加上大括号,即利用代码块调用析构得结果
让消耗线程慢一点取,消耗线程后面加上sleep(400);运行结果
void Data_Consume_Thread()
{
while (true)
{
unique_lock<mutex> ul(mut);//上锁 条件变量 搭配使用的就是unique_lock,我还没学透彻就不献丑了
cond.wait(ul, [] {return !data_que.empty();});
//条件变量发挥作用:如果队列为空,返回假,此线程就会进入阻塞状态,解锁,等待产生线程生产数据
int tmp = data_que.front();
data_que.pop();
cout << "消费线程:消耗" << tmp << endl;
ul.unlock();
}
}
int main()
{
thread t1 = thread(Data_Produce_Thread);
thread t2 = thread(Data_Consume_Thread);
t1.detach(); //让t1自己去执行 主线程不等他
t2.detach();
Sleep(5000); //window.h中的函数 睡眠5s
System("pause");
}