IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【C++】多线程(链式、循环队列)实现生产者消费者模式 -> 正文阅读

[Java知识库]【C++】多线程(链式、循环队列)实现生产者消费者模式

生产者消费者模式:

????????生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
?

这是我在Linux多线程中写过的一篇文章,里面详细讲解了信号量和互斥锁解决多线程的生产者与消费者模式:

Linux信号量与互斥锁解决生产者与消费者问题_神厨小福贵!的博客-CSDN博客先来看什么是生产者消费者问题:生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据https://blog.csdn.net/qq_45829112/article/details/121580819下图就是生产者消费者的大致模型:

上图所示,我们能不能在【C++】中使用多线程使得,一边生产,一边消费呢???

关于【C++】多线程,我在之前一篇中说过:

【C++】多线程thread_神厨小福贵!的博客-CSDN博客进程和线程的区别:进程是资源分配的最小单位,线程是CPU调度的最小单位 进程有自己的独立地址空间,线程共享进程中的地址空间 进程的创建消耗资源大,线程的创建相对较小进程的切换开销大,线程的切换开销相对较小 进程:程序执行的过程叫进程。线程:进程内部的一条执行序列或执行路径,一个进程可以包含多条线程(多线程)!每个进程最少有一个线程,例如下面代码:#include <iostream>using namespace std; int main(){ https://blog.csdn.net/qq_45829112/article/details/123521502?spm=1001.2014.3001.5502

下面我们拿链队列循环队列分别实现我们的生产者消费者模式

链队列实现生产者消费者:queue来实现:

const int MAX_ITEM = 20;  //双端队列最大长度
std::mutex mx;   //全局锁
std::condition_variable cv;  //条件变量cv
class Queue  
{
public:
	void put(int val, int index)  //入队函数
	{
		std::unique_lock<std::mutex> lock(mx);  //类似于智能指针的智能锁,不需要手动解锁
		while (q.size() == MAX_ITEM)  //队列满了之后,等待
		{
			cv.wait(lock);
		}
		q.push_back(val);  //入队
		cv.notify_all();  //唤醒
		cout << "producer: " << index << "val : " << "生产者" << val << endl;
	} 
	int get(int index)   //出队函数
	{
		unique_lock<std::mutex> lock(mx); //类似于智能指针的智能锁,不需要手动解锁
		while (q.empty())  //队列空了等待
		{
			cv.wait(lock);
		}
		int val = q.front();  //出队函数
		q.pop_front();  //队头出,队尾加
		cv.notify_all();
		cout << "Consumer : " << index << " val : " << val << endl;
		return val;
	}
private:
	deque<int> q;
};
void producer(Queue* q, int index)
{
	for (int i = 0; i < 100; ++i)
	{
		q->put(i, index);  //调用class queue中的put函数
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
}
void consumer(Queue* q, int index)
{
	for (int i = 0; i < 100; ++i)
	{
		q->get(index);  //调用class queue中的get函数
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
}
int main()
{
	Queue* q = new Queue();
	thread p1(producer, q, 1);
	thread s1(consumer, q, 1);
	p1.join();
	s1.join();
	return 0;
}

这个代码也比较简单,就不多说了,上面注释也很详细!!!

看一下运行结果:因为我在消费者函数和生产者函数中的睡眠时间都是100,所以我们的生产者和消费者就是生产一个,消费一个这个情况

?循环队列实现生产者消费者:

下图是循环队列的大致示意图:

?下面来代码:

template<class T>  //模板类
class Queue
{
	enum { QUSIZE = 8 };  //循环队列大小为8

	T* data;   //指针指向循环队列连续空间
	int front;  //队头
	int rear;  //队尾
	int size;  //当前队列的元素个数
	int maxsize;  //队列最大大小
public:
	Queue() :data(nullptr), front(0), rear(0), size(0), maxsize(QUSIZE)
	{
		data = new T[maxsize];
	}
	~Queue()
	{
		free(data);
		data = nullptr;
		front = rear = -1;
		size = 0;
		maxsize = 0;
	}

	int Capt() const { return maxsize; }    //求队列最大元素个数的函数
	int Size() const { return size; }   //求现有元素个数的函数
	bool Empty() const { return Size() == 0; }  //判空函数
	bool Full() const {             //判满函数
		return Size() == maxsize;
	}
	bool Push(const T& val)     //入队函数
	{
		if (Full()) return false;
		data[rear] = val;
		rear = (rear + 1) % maxsize;  //上面说到最大值为8,也就是说存储下标为0到7
		size += 1;
		return true;
	}
	bool Front(T& val)  //出队函数
	{
		if (Empty()) return false;
		val = data[front];
		front = (front + 1) % maxsize;//上面说到最大值为8,也就是说存储下标为0到7
		size -= 1;
		return true;
	}
};

Queue<int> iq;  //实例化iq
std::mutex mx;  //全局锁mx
std::condition_variable cv;  //条件变量cv
const int maxsize = iq.Capt();  //最大元素个数

int number = 0; // 100;
void producer(int index)
{
	std::unique_lock<std::mutex> lock(mx);  //类似于智能指针的智能锁
	for (int i = 0; i < 100; i++)
	{
		cv.wait(lock, []()->bool {return !iq.Full(); });  //lambda表达式
		iq.Push(number);  //上述lambda表达式为真退出,所以就不为full时为退出
		cout << "product " << number << endl;
		number++;
		cv.notify_all();
	}
}

void consumer(int index)
{
	std::unique_lock<std::mutex> lock(mx);
	for (int i = 0; i < 100; i++)
	{
		cv.wait(lock, []()->bool {return !iq.Empty(); });//lambda表达式中为真退出等待不为NULL时,退出wait
        int val = 0;
		iq.Front(val);
		cout << "consumer " << val << endl;
		cv.notify_all();
	}
}

int main()

{
	std::thread pth1(producer, 1);  //生产者
	std::thread pth2(consumer, 2);  //消费者

	pth1.join();
	pth2.join();

	return 0;
}

运行结果:?

?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:21:20  更:2022-03-24 00:25:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:30:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码