Studying-多线程学习Part3 - condition_variable与其使用场景、C++11实现跨平台线程池

news2024/12/24 1:02:07

来源:多线程学习

目录

condition_variable与其使用场景 

生产者与消费者模型

C++11实现跨平台线程池 


condition_variable与其使用场景 

生产者与消费者模型

生产者-消费者模式是一种经典的多线程设计模式,用于解决多个线程之间的数据共享和协作问题。在生产者-消费者模式中,有两类线程:生产者线程和消费者线程。它们之间通过共享一个缓冲区(或队列)来协作,生产者将数据放入缓冲区,消费者从缓冲区取出数据并进行处理。

生产者-消费者模式的主要目标是实现生产者和消费者之间的解耦,使它们可以独立地进行工作,从而提高系统的性能和可维护性。

condition_variable的步骤如下:

  1. 创建一个condition_variable对象
  2. 创建一个互斥锁 mutex 对象,用来保护共享资源的访问。
  3. 在需要等待条件变量的地方:使用unique_lock<mutex>对象锁定互斥锁,并调用condition_variable::wait()、condition_variable::wait_for()或condition_variable::wait_until()函数等待条件变量。

  4. 在其他线程中需要通知等待的线程时,调用condition_variable::notify_one()或condition_variable::notify_all()函数通知等待的线程。

代码参考:

#include <iostream>
#include <thread>
#include <mutex>
#include <string>

#include <condition_variable>
#include <queue>
using namespace std;

queue<int> g_queue; //任务队列
condition_variable g_cv;
mutex mtx;


//实现生产者
void Producer() {
	for (int i = 0; i < 10; ++i) {
		{
			unique_lock<mutex> lock(mtx);
			g_queue.push(i);
			//加任务的时候哦,需要通知消费者来取任务
			g_cv.notify_one(); 
			cout << "Producer: " << i << endl;
		}
		this_thread::sleep_for(chrono::microseconds(100)); //休眠100ms
	}
}

//实现消费者
void Consumer() {
	while (1) {
		unique_lock<mutex> lock(mtx);

		//如果队列为空,理应需要等待
		//第二个参数是函数指针(可以用lambda表达式)返回的true则不堵塞,false则阻塞,注意阻塞的时候会释放资源所以不会发生死锁
		g_cv.wait(lock, []() {return !g_queue.empty(); });
		int value = g_queue.front();
		g_queue.pop();

		cout << "Consumer:" << value << endl;
	}
}

int main() {
	thread t1(Producer);
	thread t2(Consumer);
	t1.join();
	t2.join();
	return 0;
}

C++11实现跨平台线程池 

线程池符合的就是生产者和消费者模型。线程池提前维护一个线程的数组和一个任务队列,不同的让线程去完成队列里的任务。

使用线程池可以解决不断销毁创建线程的消耗。

代码参考:

//实现线程池
#include <iostream>
#include <thread>
#include <mutex>
#include <string>
#include <condition_variable> //条件变量
#include <queue>
#include <thread>
#include<functional> //对象包装器
using namespace std;

//创先线程池的类
class ThreadPool {
public:
	//构造函数
	ThreadPool(int numThreads) : stop(false) {
		for (int i = 0; i < numThreads; i++) {
			threads.emplace_back([this] {
				while (1) {
					unique_lock<mutex> lock(mtx); //互斥锁,因为线程是操作任务队列的
					condition.wait(lock, [this] { //判断任务队列里面是否有任务,且是否停止
						return !tasks.empty() || stop;
						});

					if (stop && tasks.empty()) { //如果线程终止了,则结束线程
						return;
					}

					function<void()> task(move(tasks.front())); //拷贝构造,但是使用move能够防止赋值
					tasks.pop();
					lock.unlock(); //取完任务之后,解锁,让其他线程可以接续取任务
					task();
				}
				});
		}
	}
	//析构函数
	~ThreadPool() {
		//手动加{}提供作用域
		{
			unique_lock<mutex> lock(mtx);
			stop = true;
		}

		condition.notify_all(); //通知线程完成所有任务
		for (thread& t : threads) { //这个地方要使用引用,因为线程是不可以复制的
			t.join();
		}
	}
	//加任务,加函数,使用模版可以实现可变参数
	template<class F,class... Args>
	void enqueue(F&& f, Args&&...args) { //&&万能引用
		function<void()> task = bind(forward<F>(f), forward<Args>(args)...);
		{
			unique_lock <mutex> lock(mtx);
			tasks.emplace(move(task));
		}
		condition.notify_one();
	}


private:
	vector<thread> threads; //线程数组
	queue<function<void()>> tasks; //任务队列,队列里面包含的是函数模版
	mutex mtx; //互斥量
	condition_variable condition; //条件变量

	bool stop;

};

int main() {
	ThreadPool pool(4);
	for (int i = 0; i < 10; i++) {
		pool.enqueue([i] {
			cout << "task: " << i << " start" << endl;
			this_thread::sleep_for(chrono::seconds(1));
			cout << "task: " << i << " down" << endl;
			});
	}

	return 0;
}

知识点汇总:

1. thread线程库:vector<thread> threads; //线程数组

2.function函数模版:

3.mutex互斥锁

4.condtion_variable 条件变量:解决生产者消费者问题

5.lambda表达式-匿名函数

6.move移动语义

7.template<class F, class...Args>

8.&&右值引用,万能引用

9.bind函数适配器,绑定函数和函数参数

10.forward完美转发,配合&&实现万能引用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2195889.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

『网络游戏』动态界面制作创建角色UI【02】

将上一章的登录界面隐藏 创建空物体重命名为CreateWnd 自适应铺满父物体 创建image重命名为bg并铺满 将以下资源图片放进Art文件夹 设置为精灵模式 填充背景 创建介绍Image面板与角色按钮 制作将3D模型动态防止UI界面上 首先创建RawImage 创建RenderTextures文件夹 创建Render…

输电线路缺陷图像检测数据集,导线散股,塔材锈蚀两类,分别为581张和1407张,标注为xml和txt格式 1988张

输电线路缺陷图像检测数据集&#xff0c;分为导线散股&#xff0c;塔材锈蚀两类&#xff0c;分别为581张和1407张&#xff0c;标注为xml和txt格式 数据集名称 输电线路缺陷图像检测数据集 (Transmission Line Defect Detection Dataset) 数据集概述 该数据集是一个专门用于训…

红队apt--文本宏病毒攻击思路整理

免责声明:本文仅用于了解攻击方手法&#xff0c;用于提高防范意识。禁止用于非法用途 前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要整理文本类病毒攻击思路 宏简介 这个东西可以直接当做编程理解。用于创建模版(简历模版),定制化需求&#xff0c;自…

【数据管理】DAMA-元数据专题

导读&#xff1a;元数据是关于数据的组织、数据域及其关系的信息&#xff0c;是描述数据的数据。在数据治理中&#xff0c;元数据扮演着至关重要的角色&#xff0c;是数据治理的基础和支撑。以下是对数据治理中元数据专题方案的详细介绍&#xff1a; 目录 一、元数据的重要性 …

基于STM32的智能门锁控制系统设计

引言 本项目基于STM32微控制器设计了一个智能门锁控制系统&#xff0c;用户可以通过密码输入或指纹识别来控制门锁的开关。该系统集成了键盘、指纹传感器、舵机等外设&#xff0c;实现了门锁的安全、便捷控制&#xff0c;同时也具备了较强的扩展性。该项目展示了STM32在安防领…

基于STM32的智能水族箱控制系统设计

引言 本项目基于STM32微控制器设计一个智能水族箱控制系统。该系统能够通过传感器监测水温、照明和水位&#xff0c;并自动控制加热器、LED灯和水泵&#xff0c;确保水族箱内的环境适宜鱼类生长。该项目展示了STM32在环境监测、设备控制和智能反馈系统中的应用。 环境准备 1…

Java:数据结构-初始结合框架 时间复杂度和空间复杂度 初识泛型

一 初始结合框架 1.什么是Java的集合框架 Java 的集合框架&#xff08;Java Collection Framework&#xff0c;JCF&#xff09;是 Java 标准库中的一部分&#xff0c;用于存储和操作一组数据。它提供了一些常用的数据结构和接口&#xff0c;用来高效管理和操作数据。Java 的…

全面图解Docker架构设计:掌握Docker全链路思维与优化(命令篇)

Docker 是一个革命性的开放平台&#xff0c;用于开发、交付和运行应用程序。通过使用 Docker&#xff0c;开发者可以打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何支持 Docker 的环境中&#xff0c;在不同环境中实现一致的运行。无论是在虚…

ctf.bugku - POST

题目来源 &#xff1a;POST - Bugku CTF 访问请求&#xff0c;返回如下信息&#xff1b; 从这里可以得到信息&#xff1b;想要得到flag &#xff0c;需要发送post请求&#xff0c;并且请求带有what参数&#xff0c;参数值为flag 构造消息体&#xff1b; burpsuite中&#x…

运用MinIO技术服务器实现文件上传——利用程序上传图片(二 )

在上一篇文章中&#xff0c;我们已经在云服务器中安装并开启了minio服务&#xff0c;本章我们将为大家讲解如何利用程序将文件上传到minio桶中 下面介绍MinIO中的几个核心概念&#xff0c;这些概念在所有的对象存储服务中也都是通用的。 - **对象&#xff08;Object&#xff0…

C++笔记之原子操作

C++笔记之原子操作 code review! 文章目录 C++笔记之原子操作1.初始化2.赋值3.取值4.赋给另一个原子类型5.`exchange`6.`compare_exchange_weak` 和 `compare_exchange_strong`使用场景7.注意事项在 C++ 中,原子类型提供了对共享变量的无锁操作,确保多线程环境下的安全。以下…

Android Automotive(一)

目录 什么是Android Automotive Android Automotive & Android Android Automotive 与 Android Auto 什么是Android Automotive Android Automotive 是一个基础的 Android 平台&#xff0c;它能够运行预装的车载信息娱乐系统&#xff08;IVI&#xff09;应用程序&#…

LeetCode讲解篇之1043. 分隔数组以得到最大和

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 对于这题我们这么考虑&#xff0c;我们选择以数字的第i个元素做为分隔子数组的右边界&#xff0c;我们需要计算当前分隔子数组的长度为多少时能让数组[0, i]进行分隔数组的和最大 我们用数组f表示[0, i)区间内的…

【C++】函数重载+引用

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解C的函数重载和引用&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一. 预处理、编译、汇编、链接二. 函数重载1 概念2 C支持函数重载的原理—名字修饰…

『网络游戏』制作加载进度UI【04】

将上一章的提示界面隐藏 创建空节点重命名为LoadingWnd 设置父物体为伸展 创建一个image背景重命名为bg 将以下资源放进Art文件夹 设为精灵模式后拖拽 将下面资源图片放进Art文件夹 创建Image作为进度条重命名为loadingbg 复制一份重命名为loadingfg 将loadingfg设置为水平填充…

Stable Diffusion绘画 | AI 图片智能扩充

来到「文生图」页面&#xff0c;输入固定的起手式提示词。 第1步&#xff0c;开启 ControlNet&#xff0c;将需要扩充的图片加载进来&#xff1a; 控制类型选择「Inpaint」&#xff0c;预处理器选择「inpaint_onlylama」&#xff0c;缩放模式选择「缩放后填充空白」&#xff1…

OpenStack Yoga版安装笔记(十六)Openstack网络理解

0、前言 本文将以Openstack在Linux Bridge环境下的应用为例进行阐述。 1、Openstack抽象网络 OpenStack的抽象网络主要包括网络&#xff08;network&#xff09;、子网&#xff08;subnet&#xff09;、端口&#xff08;port&#xff09;&#xff0c;路由器&#xff08;rout…

Android15车载音频之Virtualbox中QACT实时调试(八十八)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

Python--暂停一秒输出

在编程实践中&#xff0c;我们经常需要让程序在执行特定操作后暂停一段时间。Python中的time模块提供了一个简单而强大的sleep()函数&#xff0c;允许程序暂停指定的时间。本文将通过一个具体的例子&#xff0c;展示如何使用sleep()函数来实现每隔一秒输出一次当前时间的最后两…

爱心曲线公式大全

local r a*((math.sin(angle) * math.sqrt(math.abs(math.cos(angle)))) / (math.sin(angle) 1.4142) - 2 * math.sin(angle) 2) local x r * math.cos(angle) -- 计算对应的x值 local z r * math.sin(angle) 1.5*a - --曲线公式绘画 local function generateParabola()…