初次使用多线程mutex编程心得

下次学习内容再写博客
立个flag:从现在开始 每天学习的内容及时写博客记录,为了方便以后复习相关内容时有帮助。刚自学多线程编程,博客中难免有错误。如果有幸有大佬看到 还望指正。

初次使用mutex
c++11中新增了mutex,condition_variable库,里面有互斥锁,条件变量以及其他和多线程有关的函数。有待探索…

代码功能简介:开辟俩个线程,模拟生产者消费者模型,生产线程产生随机数据,插入到队列中。消费线程消耗数据,从队列中拿走数据。由于要对同一个队列操作,也就是多线程编程中的“临界区”操作,所以需要上锁,以避免出现各种奇怪的错误。 (有时候队列中一个数取出来俩次,有时候取出来一个没插进去的数。等)

先上代码

#include <thread>
#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");
}

猜你喜欢

转载自blog.csdn.net/MikeBoat/article/details/88121141