C++常用多线程模式

文章目录

      • 1. Fork - Join模式
      • 2. Producer - Consumer模式
      • 3. Readers - Writers模式
      • 4. Work Thread模式
      • 5. Actor模式
      • 6、 Pipeline模式概述
      • 应用场景
      • C++实现示例
      • 代码解释

1. Fork - Join模式

  • 原理:将一个大任务分解为多个子任务,这些子任务在不同的线程中并行执行,当所有子任务完成后,再将它们的结果合并得到最终结果。
  • 优点:充分利用多核处理器的并行能力,提高计算效率;任务分解和结果合并的过程清晰,便于理解和实现分治算法等。
  • 缺点:需要考虑子任务的划分合理性以及线程间的同步问题,以确保结果的正确性。
  • 适用场景:适用于能有效分解为多个独立子任务的计算密集型任务,如大规模数据处理、科学计算中的矩阵运算等。
#include <iostream>
#include <vector>
#include <thread>
#include <numeric>// 计算数组某区间的和
void sum_subarray(const std::vector<int>& arr, int start, int end, int& result) {result = std::accumulate(arr.begin() + start, arr.begin() + end, 0);
}int main() {std::vector<int> arr(1000);std::iota(arr.begin(), arr.end(), 1);int mid = arr.size() / 2;int left_sum = 0, right_sum = 0;// Fork: 创建两个线程分别计算左右子数组的和std::thread left_thread(sum_subarray, std::ref(arr), 0, mid, std::ref(left_sum));std::thread right_thread(sum_subarray, std::ref(arr), mid, arr.size(), std::ref(right_sum));// Join: 等待两个线程完成left_thread.join();right_thread.join();int total_sum = left_sum + right_sum;std::cout << "Total sum: " << total_sum << std::endl;return 0;
}

2. Producer - Consumer模式

  • 原理:生产者线程负责生产数据并将其放入缓冲区,消费者线程从缓冲区取出数据进行处理。通过缓冲区实现生产者和消费者的解耦,使它们可以以不同的速度运行。
  • 优点:提高了程序的并发度和整体性能,生产者和消费者可以独立优化和扩展,代码可读性和维护性较好。
  • 缺点:需要合理设计缓冲区大小和同步机制,避免缓冲区溢出或不足,同时要处理好生产者和消费者之间的同步与互斥问题。
  • 适用场景:广泛应用于各种数据处理场景,如文件读取与处理、网络数据的接收与解析、消息队列系统等。
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>std::queue<int> task_queue;
std::mutex mtx;
std::condition_variable cv;
bool is_running = true;// 生产者函数
void producer() {for (int i = 0; i < 10; ++i) {std::this_thread::sleep_for(std::chrono::milliseconds(100));{std::unique_lock<std::mutex> lock(mtx);task_queue.push(i);std::cout << "Produced: " << i << std::endl;}cv.notify_one();}{std::unique_lock<std::mutex> lock(mtx);is_running = false;}cv.notify_all();
}// 消费者函数
void consumer() {while (true) {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [] { return!task_queue.empty() ||!is_running; });if (task_queue.empty() &&!is_running) {break;}int task = task_queue.front();task_queue.pop();std::cout << "Consumed: " << task << std::endl;}
}int main() {std::thread producer_thread(producer);std::thread consumer_thread(consumer);producer_thread.join();consumer_thread.join();return 0;
}

3. Readers - Writers模式

  • 原理:允许多个读者线程同时访问共享资源,但当有写者线程访问时,所有读者和其他写者都需等待。写者线程具有更高的优先级,以确保数据的一致性。
  • 优点:能有效提高对共享资源的访问效率,在有大量读操作和少量写操作的情况下,能充分利用多核处理器的并行性。
  • 缺点:实现较为复杂,需要精细地控制读写线程的同步与互斥,以避免数据不一致和死锁等问题。
  • 适用场景:常用于数据库系统、文件系统等需要频繁读写共享数据的场景,其中读操作远远多于写操作。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex rw_mutex;
std::condition_variable rw_cv;
int readers = 0;
bool writer_active = false;// 读者函数
void reader(int id) {{std::unique_lock<std::mutex> lock(rw_mutex);rw_cv.wait(lock, [] { return!writer_active; });++readers;}std::cout << "Reader " << id << " is reading." << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));{std::unique_lock<std::mutex> lock(rw_mutex);--readers;if (readers == 0) {rw_cv.notify_one();}}
}// 写者函数
void writer(int id) {{std::unique_lock<std::mutex> lock(rw_mutex);rw_cv.wait(lock, [] { return!writer_active && readers == 0; });writer_active = true;}std::cout << "Writer " << id << " is writing." << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));{std::unique_lock<std::mutex> lock(rw_mutex);writer_active = false;rw_cv.notify_all();}
}int main() {std::thread r1(reader, 1);std::thread r2(reader, 2);std::thread w1(writer, 1);std::thread r3(reader, 3);r1.join();r2.join();w1.join();r3.join();return 0;
}

4. Work Thread模式

  • 原理:有一个任务队列,多个工作线程从队列中获取任务并执行。任务队列可以是优先级队列或普通队列,工作线程根据一定的规则从队列中取出任务进行处理。
  • 优点:实现相对简单,易于扩展工作线程的数量来应对不同的负载需求,能有效利用线程资源,避免线程的频繁创建和销毁。
  • 缺点:任务队列的管理和线程的调度需要一定的开销,可能会出现任务饥饿现象,即某些低优先级任务长时间得不到执行。
  • 适用场景:适用于处理大量异步任务的场景,如网络服务器中的请求处理、分布式系统中的任务调度等。
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <vector>std::queue<std::function<void()>> work_queue;
std::mutex queue_mutex;
std::condition_variable queue_cv;
bool is_working = true;// 工作线程函数
void worker() {while (true) {std::function<void()> task;{std::unique_lock<std::mutex> lock(queue_mutex);queue_cv.wait(lock, [] { return!work_queue.empty() ||!is_working; });if (work_queue.empty() &&!is_working) {break;}task = std::move(work_queue.front());work_queue.pop();}task();}
}int main() {std::vector<std::thread> workers;for (int i = 0; i < 3; ++i) {workers.emplace_back(worker);}// 添加任务到队列{std::unique_lock<std::mutex> lock(queue_mutex);for (int i = 0; i < 5; ++i) {work_queue.emplace([i] {std::cout << "Task " << i << " is being executed." << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));});}}queue_cv.notify_all();// 等待所有任务完成{std::unique_lock<std::mutex> lock(queue_mutex);is_working = false;}queue_cv.notify_all();for (auto& t : workers) {t.join();}return 0;
}

5. Actor模式

  • 原理:将整个处理过程分为多个阶段,每个阶段由一个或多个Actor(参与者)负责。数据在这些Actor之间像流水线一样依次传递,每个Actor处理完数据后将其传递给下一个Actor,直到最终处理完成。
  • 优点:提高了系统的吞吐量和响应性,各个阶段可以并行执行,而且易于维护和扩展,每个Actor可以独立开发和测试。
  • 缺点:需要精心设计流水线的各个阶段和数据传递方式,以确保数据的正确流转和系统的稳定性。
  • 适用场景:适用于处理流程较为复杂且可以明确划分为多个阶段的任务,如视频编码解码、图像处理流水线、网络数据包的处理等。
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>// 第一个阶段 Actor
class FirstActor {
public:std::queue<int> input_queue;std::mutex mtx;std::condition_variable cv;bool is_finished = false;void run() {for (int i = 0; i < 5; ++i) {std::this_thread::sleep_for(std::chrono::milliseconds(100));{std::unique_lock<std::mutex> lock(mtx);input_queue.push(i);}cv.notify_one();}{std::unique_lock<std::mutex> lock(mtx);is_finished = true;}cv.notify_all();}
};// 第二个阶段 Actor
class SecondActor {
public:FirstActor& first_actor;std::queue<int> output_queue;std::mutex mtx;std::condition_variable cv;bool is_finished = false;SecondActor(FirstActor& fa) : first_actor(fa) {}void run() {while (true) {int data;{std::unique_lock<std::mutex> lock(first_actor.mtx);first_actor.cv.wait(lock, [this] { return!first_actor.input_queue.empty() || first_actor.is_finished; });if (first_actor.input_queue.empty() && first_actor.is_finished) {break;}data = first_actor.input_queue.front();first_actor.input_queue.pop();}data *= 2;{std::unique_lock<std::mutex> lock(mtx);output_queue.push(data);}cv.notify_one();}{std::unique_lock<std::mutex> lock(mtx);is_finished = true;}cv.notify_all();}
};// 第三个阶段 Actor
class ThirdActor {
public:SecondActor& second_actor;ThirdActor(SecondActor& sa) : second_actor(sa) {}void run() {while (true) {int data;{std::unique_lock<std::mutex> lock(second_actor.mtx);second_actor.cv.wait(lock, [this] { return!second_actor.output_queue.empty() || second_actor.is_finished; });if (second_actor.output_queue.empty() && second_actor.is_finished) {break;}data = second_actor.output_queue.front();second_actor.output_queue.pop();}std::cout << "Final result: " << data << std::endl;}}
};int main() {FirstActor first_actor;SecondActor second_actor(first_actor);ThirdActor third_actor(second_actor);std::thread t1(&FirstActor::run, &first_actor);std::thread t2(&SecondActor::run, &second_actor);std::thread t3(&ThirdActor::run, &third_actor);t1.join();t2.join();t3.join();return 0;
}

6、 Pipeline模式概述

Pipeline(流水线)模式是一种将一个复杂任务分解为多个独立子任务,并让这些子任务像流水线一样依次执行的设计模式。每个子任务负责处理一部分工作,处理完后将结果传递给下一个子任务,最终完成整个复杂任务。这种模式可以提高系统的并发性能和可维护性,因为每个子任务可以独立开发、测试和优化,而且不同的子任务可以并行执行。

应用场景

  • 数据处理流程:例如在图像或视频处理中,一个完整的处理流程可能包括图像读取、降噪、增强、裁剪等多个步骤,每个步骤可以作为一个独立的子任务在流水线上执行。
  • 网络请求处理:在网络服务器中,一个请求可能需要经过接收、解析、验证、业务逻辑处理、响应生成等多个阶段,使用流水线模式可以高效地处理大量请求。

C++实现示例

以下是一个简单的C++示例,模拟一个简单的数据处理流水线,包含三个子任务:数据生成、数据处理和数据输出。

#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>// 第一个阶段:数据生成
class DataGenerator {
public:std::queue<int> outputQueue;std::mutex mtx;std::condition_variable cv;bool isFinished = false;void run() {for (int i = 0; i < 10; ++i) {std::this_thread::sleep_for(std::chrono::milliseconds(100));{std::unique_lock<std::mutex> lock(mtx);outputQueue.push(i);}cv.notify_one();}{std::unique_lock<std::mutex> lock(mtx);isFinished = true;}cv.notify_all();}
};// 第二个阶段:数据处理
class DataProcessor {
public:DataGenerator& generator;std::queue<int> outputQueue;std::mutex mtx;std::condition_variable cv;bool isFinished = false;DataProcessor(DataGenerator& gen) : generator(gen) {}void run() {while (true) {int data;{std::unique_lock<std::mutex> lock(generator.mtx);generator.cv.wait(lock, [this] { return!generator.outputQueue.empty() || generator.isFinished; });if (generator.outputQueue.empty() && generator.isFinished) {break;}data = generator.outputQueue.front();generator.outputQueue.pop();}// 简单的数据处理,这里将数据加倍data *= 2;{std::unique_lock<std::mutex> lock(mtx);outputQueue.push(data);}cv.notify_one();}{std::unique_lock<std::mutex> lock(mtx);isFinished = true;}cv.notify_all();}
};// 第三个阶段:数据输出
class DataOutputter {
public:DataProcessor& processor;DataOutputter(DataProcessor& proc) : processor(proc) {}void run() {while (true) {int data;{std::unique_lock<std::mutex> lock(processor.mtx);processor.cv.wait(lock, [this] { return!processor.outputQueue.empty() || processor.isFinished; });if (processor.outputQueue.empty() && processor.isFinished) {break;}data = processor.outputQueue.front();processor.outputQueue.pop();}std::cout << "Processed data: " << data << std::endl;}}
};int main() {DataGenerator generator;DataProcessor processor(generator);DataOutputter outputter(processor);std::thread generatorThread(&DataGenerator::run, &generator);std::thread processorThread(&DataProcessor::run, &processor);std::thread outputterThread(&DataOutputter::run, &outputter);generatorThread.join();processorThread.join();outputterThread.join();return 0;
}

代码解释

  1. DataGenerator类:负责生成数据,将生成的数据放入输出队列outputQueue,并通过条件变量cv通知下一个阶段有新数据可用。
  2. DataProcessor类:从DataGenerator的输出队列中获取数据,对数据进行处理(这里简单地将数据加倍),然后将处理后的数据放入自己的输出队列,并通知下一个阶段。
  3. DataOutputter类:从DataProcessor的输出队列中获取数据,并将其输出到控制台。
  4. main函数:创建三个线程分别运行三个阶段的任务,并等待所有线程执行完毕。

通过这种方式,数据在三个阶段之间依次传递,形成了一个简单的流水线。每个阶段可以独立运行,提高了系统的并发性能。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EasyRTC轻量级Webrtc音视频通话SDK,助力带屏IPC在嵌入式设备中的应用

一、市场背景 随着人们生活水平的提高&#xff0c;对于家居安全和远程监控的需求日益增长&#xff0c;带屏IPCam不仅满足了用户实时查看监控画面的需求&#xff0c;还提供了诸如双向语音通话、智能报警等丰富的功能&#xff0c;极大地提升了用户体验。 此外&#xff0c;技术的…

Linux安装JDK

1、下载JDK https://www.oracle.com/cn/java/technologies/downloads/#java11 2、安装 2.1、创建安装目录 mkdir /usr/local/jdk 2.1、将下载的tar.gz上传到服务器 使用tar -zxvf jdk-8u311-linux-x64.tar.gz解压后剪切到 /usr/local/jdk目录&#xff1a;mv xxx /usr/local/j…

基于基于eFish-SBC-RK3576工控板的智慧城市边缘网关

此方案充分挖掘eFish-SBC-RK3576的硬件潜力&#xff0c;可快速复制到智慧园区、交通枢纽等场景。 方案亮点 ‌接口高密度‌&#xff1a;单板集成5GWiFi多路工业接口&#xff0c;减少扩展复杂度。‌AIoT融合‌&#xff1a;边缘端完成传感器数据聚合与AI推理&#xff0c;降低云端…

CSS 学习笔记 - 蓝桥杯重点整理

1. CSS 基础语法 核心知识点 选择器 声明块结构三种引入方式&#xff1a;行内/内部/外部常用选择器类型&#xff1a;标签/类/ID/通配符 <!-- 行内样式 --> <p style"color: red;">红色文字</p><!-- 内部样式 --> <style>/* 标签选…

UML的使用

process on 在线使用 UML概念 UML &#xff1a;统一建模语言(Unified Modeling Language&#xff0c;是用来设计软件的可视化建模语言。 1. 类图 1.1 概念 类图&#xff08;Class Diagram&#xff09;是UML中用于描述系统静态结构的图形化工具。它展示了系统的类、接口、它…

【C++】入门

1.命名空间 1.1 namespace的价值 在C/C中&#xff0c;变量&#xff0c;函数和后面要学到的类都是大量存在的&#xff0c;这些变量&#xff0c;函数和类的名称将存在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化&#xff0c;…

数据库练习2

目录 1.向heros表中新增一列信息&#xff0c;添加一些约束&#xff0c;并尝试查询一些信息 2.课堂代码练习 插入语句 INSERT INTO 删除语句DELETE和TRUNCATE 更新语句UPDATE和replace 查询语句SELECT 条件查询 查询排序 聚合函数 分组查询 3.题目如下 一、单表查询 …

w266农产品直卖平台的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

2025新版懒人精灵零基础安装调试+lua基础+UI设计交互+常用方法封装+项目实战+项目打包安装板块-视频教程(初学者必修课)

2025新版懒人精灵零基础安装调试lua基础UI设计交互常用方法封装项目实战项目打包安装板块-视频教程(初学者必修课)&#xff1a; 1.懒人精灵核心API基础和lua基础视频教程&#xff1a;https://www.bilibili.com/video/BV1Vm9kYJEfM/ 温馨提示&#xff1a;所有视频请用电脑浏览…

CCF-CSP认证 202206-2寻宝!大冒险!

题目描述 思路 有一张绿化图和藏宝图&#xff0c;其中绿化图很大&#xff08;二维数组在限定的空间内无法存储&#xff09;&#xff0c;而藏宝图是绿化图中的一部分&#xff0c;对于绿化图和藏宝图&#xff0c;左下角的坐标为(0, 0)&#xff0c;右上角的坐标是(L, L)、(S, S)&…

Qt下集成大华网络相机SDK示例开发

文章目录 前言一、下载并集成大华网络相机SDK二、示例实现功能三、示例完整代码四、下载链接总结 前言 近期在Qt环境下进行大华网络相机的使用&#xff0c;发现官网下载的SDK中提供的示例没有Qt的demo&#xff0c;通过学习其提供的MFC示例代码&#xff0c;我在这里也实现了一个…

[学习笔记] 部署Docker搭建靶场

前言 我们需要部署Docker来搭建靶场题目&#xff0c;他可以提供一个隔离的环境&#xff0c;方便在不同的机器上部署&#xff0c;接下来&#xff0c;我会记录我的操作过程&#xff0c;简单的部署一道题目 Docker安装 不推荐在物理机上部署&#xff0c;可能会遇到一些问题&…

网络华为HCIA+HCIP IPv6

目录 IPv4现状 IPv6基本报头 IPv6扩展报头 IPv6地址 IPv6地址缩写规范 ​编辑 IPv6地址分配 IPv6单播地址分配 IPv6单播地址接口标识 IPv6常见单播地址 - GUA &#xff08;2 / 3 开头&#xff09; IPv6常见单播地址 - ULA IPv6常见单播地址 - LLA IPv6组播地…

可视化动态表单动态表单界的天花板--Formily(阿里开源)

文章目录 1、Formily表单介绍2、安装依赖2.1、安装内核库2.2、 安装 UI 桥接库2.3、Formily 支持多种 UI 组件生态&#xff1a; 3、表单设计器3.1、核心理念3.2、安装3.3、示例源码 4、场景案例-登录注册4.1、Markup Schema 案例4.2、JSON Schema 案例4.3、纯 JSX 案例 1、Form…

C++::多态

目录 一.多态的概念 二.多态的定义及实现 二.1多态的构成条件 二.2虚函数 1.虚函数的写法 2.虚函数的重写/覆盖 3.协变 二.3析构函数的重写 二.4override和final关键字 ​编辑二.5重载/重写/隐藏的对比 三.多态的运行原理&#xff08;一部分&#xff09; 四.多态的常…

Mistral AI发布开源多模态模型Mistral Small 3.1:240亿参数实现超越GPT-4o Mini的性能

法国人工智能初创公司Mistral AI于2025年3月正式推出新一代开源模型Mistral Small 3.1 &#xff0c;该模型凭借240亿参数的轻量级设计&#xff0c;在多项基准测试中表现优异&#xff0c;甚至超越了Google的Gemma 3和OpenAI的GPT-4o Mini等主流专有模型。 1、核心特性与优势 多…

从零开发数据可视化

一、可视化模版展示 二、知识及素材准备 div css 布局flex布局Less原生js jquery 的使用rem适配echarts基础 相关js、images、font百度网盘下载链接&#xff1a; 通过百度网盘分享的文件&#xff1a;素材1 链接: https://pan.baidu.com/s/1vmZHbhykcvfLzzQT5USr8w?pwdwjx9…

WSL git文件异常 所有文件均显示已修改

如图&#xff0c;文件中没有任何修改&#xff0c;但是都显示多了一个^M 原因&#xff1a;是因为在Windows系统中git clone的文件夹&#xff0c;在WSL中会显示冲突。 解决方案&#xff1a;删掉之前在windows下git clone的文件夹&#xff0c; 然后在WSL中重新git clone

基于STM32进行FFT滤波并计算插值DA输出

文章目录 一、前言背景二、项目构思1. 确定FFT点数、采样率、采样点数2. 双缓存设计 三、代码实现1. STM32CubeMX配置和HAL库初始化2. 核心代码 四、效果展示和后话五、项目联想与扩展1. 倍频2. 降频3. 插值3.1 线性插值3.2 样条插值 一、前言背景 STM32 对 AD 采样信号进行快…

ENSP学习day9

ACL访问控制列表实验 ACL&#xff08;Access Control List&#xff0c;访问控制列表&#xff09;是一种用于控制用户或系统对资源&#xff08;如文件、文件夹、网络等&#xff09;访问权限的机制。通过ACL&#xff0c;系统管理员可以定义哪些用户或系统可以访问特定资源&#x…