生产者消费者模型以及死锁问题

消费者与生产者由于存在于不同的线程,却要访问同一资源,所以容易访问冲突。
三种关系实现安全访问:

  • 消费者与消费者之间 互斥关系
  • 生产者与生产者之间 互斥关系
  • 生产者与消费者之间 互斥同步关系
  1. 其中互斥量(mutex)实现互斥关系。互斥量是一个标志量,一个线程对互斥量加锁,其他线程在对其加锁时就会阻塞从而实现互斥。
  2. 条件变量实现同步,但要借助互斥量。当阻塞条件满足时,条件变量阻塞当前线程,并解锁互斥量,目的是让其他线程获得互斥量,操作公共资源。 另一方面,当前线程不阻塞,操作完公共资源后靠条件变量通知其他线程,解除其他线程的阻塞状态。

c++对互斥量的加锁解锁实现了两种接口:unique_lock, lock_guard。lock_guard创建时加锁,离开作用域解锁,也就意味着整个函数体都处于单线程下。unique_lock能随时加锁解锁,在访问公共资源时加锁保证单线程访问,线程独有的操作时解锁,允许其他线程运行,提高并发行。

生产消费者模型

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

using namespace std;

const int arr_size = 2048;

struct CircleQueue
{
	int arr[arr_size];//数组做循环队列
	int read_pos;
	int write_pos;

	condition_variable cond_not_full;//表示非满的条件变量,队列满时阻塞。
	condition_variable cond_not_empty;//表示非空的条件变量,队列空时阻塞。
	mutex mtx;//保护数组的互斥量

	CircleQueue() : read_pos(0), write_pos(0) {}
} g_circleQueue;

void produceItem(CircleQueue &qu, int item)
{
	unique_lock<mutex> lock(qu.mtx); 
	while ((qu.write_pos + 1) % arr_size == qu.read_pos)
	{
		cout << "队列满..." << endl;
		qu.cond_not_full.wait(lock); //队列满时,条件变量阻塞,等待消费者线程消费数据。
	}
	//队列不满,执行生产操作。
	qu.arr[qu.write_pos] = item;
	qu.write_pos = (qu.write_pos + 1) % arr_size;
	//通知因队列空而阻塞的消费者线程。
	qu.cond_not_empty.notify_all();
	lock.unlock();
}

void consumItem(CircleQueue &qu, int& item)
{
	unique_lock<mutex> lock(qu.mtx);
	while (qu.write_pos == qu.read_pos)
	{
		cout << "队列空..." << endl;
		qu.cond_not_empty.wait(lock); //队列空时,条件变量阻塞,等待生产者线程。
	}
	//队列不空,执行消费操作
	item = qu.arr[qu.read_pos];
	qu.read_pos = (qu.read_pos + 1) % arr_size;

	qu.cond_not_full.notify_all();
	lock.unlock();
}
//每个生产线程生产3个产品
void produceTask()
{
	for (int i = 0; i < 3; i++)
	{
		this_thread::sleep_for(chrono::seconds(1));
		produceItem(g_circleQueue, i + 1);
		
		cout  << " produce " << i + 1 << endl;
	}
}

void consumTask()
{
	while (1)
	{
		int item = 0;
		consumItem(g_circleQueue, item);
		this_thread::sleep_for(chrono::seconds(1));
		cout  << " consume " << item << endl;
	}
}
int main()
{
	unique_lock<mutex> lock();
		//4生产线程
	thread producer1(produceTask);
	thread producer2(produceTask);
	thread producer3(produceTask);
	thread producer4(produceTask);
	//2消费线程
	thread consumer1(consumTask);
	thread consumer2(consumTask);

	producer1.join();
	producer2.join();
	producer3.join();
	producer4.join();
	consumer1.join();
	consumer2.join();
	return 0;
}

在判断阻塞条件时要使用while而不是if,原因是避免虚假唤醒,当多个生产者或多个消费者等在wait条件不能同时唤醒。

看到一些博客说,这种模型容易引发死锁,不知到什么情况会引发死锁,以及如何解决呢?有人能说一下吗?
互斥信号量wait应该放在资源信号量后面,过几天再改。

参考:
https://blog.csdn.net/u012507022/article/details/85909567
https://www.cnblogs.com/swarmbees/p/5889297.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值