九、Linux系统编程:线程池编程

2023-10-27

9 线程池编程

创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。

9.1 概念

线程池是提前创建并维护多个线程,等待管理者分配任务的机制,避免短时间线程创建和销毁的代价,一般是IO密集型的场景使用。主要包括线程管理器、任务线程、消息队列。

举例:安检、银行柜台等
在这里插入图片描述

  • 为什么使用线程池?
    频繁创建和销毁线程浪费CPU资源
  • 线程池是什么?
    一堆线程放在一个池子里统一管理

9.2 构成

在这里插入图片描述

9.2.1 任务队列job_queue

  • 作用
    存放待处理的任务
  • 成员
构成 接口
处理函数 void *(*)(void*)
参数 void *arg
队列指针 struct job_queue* pnext

9.2.2 工作线程worker

  • 作用
    处理任务

9.2.3 线程池thread_pool

  • 作用
    管理多个线程并提供任务队列的接口
  • 成员
构成 接口
初始化 threadpool_init()
销毁 threadpool_destroy()
添加任务 threadpool_add_job()

9.3 流程

  • 使用流程
    1、初始化线程池
    2、向线程池添加任务
    3、销毁线程池

  • 线程池初始化
    1、初始化任务队列和工作线程组
    2、将等候在条件变量(任务队列上有任务)上的一个线程唤醒并从该任务队列中取出第一个任务给该线程执行
    4、等待任务队列中所有任务执行完毕

9.4 实例

9.4.1 C++实现多线程读写

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <numeric>
#include <algorithm>
#include <condition_variable>
using namespace std;

int main() {
    mutex m;
    condition_variable cond;
    vector<int> vec;
    thread t([&]() {
        for(int i = 0; i < 10; ++i) {
            unique_lock<mutex> lock(m);
            while(vec.size()<5) cond.wait(lock); //wait
            cout << "sum:" << accumulate(vec.begin(),vec.end(),0) << endl;
            vec.clear();
        }
    });
    int n;
    while(cin >> n){
        lock_guard<mutex> lock(m);
        vec.push_back(n);
        if(vec.size()>=5) cond.notify_one(); //signal
    }
}
[root@localhost 8]# ./a.out 
1
2
3
4
5
sum:15
6
7
8
9
10
sum:40
^C

9.4.2 线程池(重要例子)

实例:

#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <functional>
using namespace std;
class Threadpool{
    vector<thread> threads; 
    queue<function<void()>> tasks;
    condition_variable cond;
    mutex m;
    bool exited = false;
public:
    Threadpool(int num){
    	for(int i = 0;i < num;++i){
	    thread t([this](){
			while(true){
		    	function<void()> func;
		    	{
		    		unique_lock<mutex> lock(m);
					while(tasks.empty() && !exited){
			   			cond.wait(lock);
					}
					if(exited) break;
		       		func = tasks.front();
					tasks.pop();
		    	}
		    	func();
			}	    
	    });
	    threads.emplace_back(move(t));
	}
    }
    ~Threadpool(){
    	exited = true;
		cond.notify_all(); //signal 通知所有
		for(auto& thread:threads){
	    	thread.join();
		}
    }
    Threadpool(const Threadpool&) = default;
    Threadpool& operator=(const Threadpool&) = default;

    void AddTask(function<void()> func){
    	lock_guard<mutex> guard(m);
		tasks.push(func);
		cond.notify_one(); //signal
    }
};
int main(){
    auto test = [](){
        this_thread::sleep_for(2s);
		cout << this_thread::get_id() << ":do something..." << endl;
    };
    Threadpool pool(5);
    for(int i = 0;i < 15;++i){
    	pool.AddTask(test);
    }
    this_thread::sleep_for(10s); //等待15个线程执行完毕
}

优化:

#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <functional>
using namespace std;
class Threadpool {
    vector<thread> threads;
    queue<function<void()>> tasks;
    condition_variable cond;
    mutex m;
    bool exited = false;
public:
    Threadpool(int num) {
        auto routine = [this]() {
            while(true) {
                unique_lock<mutex> lock(m);
                while(tasks.empty() && !exited) {
                    cond.wait(lock);
                }
                if(exited) break;
                auto func = tasks.front();
                tasks.pop();
                lock.unlock();
                func();
            }
        };
        for(int i = 0; i < num; ++i) {
            // thread t(routine);
            // threads.emplace_back(move(t));
            // threads.emplace_back(thread(routine));
            threads.emplace_back(thread{routine});
        }
    }
    ~Threadpool() {
        exited = true;
        cond.notify_all(); //signal 通知所有
        for(auto& thread:threads) {
            thread.join();
        }
    }
    Threadpool(const Threadpool&) = default;
    Threadpool& operator=(const Threadpool&) = default;

    void AddTask(function<void()> func) {
        lock_guard<mutex> guard(m);
        tasks.push(func);
        cond.notify_one(); //signal
    }
};
int main() { 
    mutex m;
    auto test = [&m]() {
        this_thread::sleep_for(2s);
		lock_guard<mutex> guard(m);
        cout << this_thread::get_id() << ":do something..." << endl;
    };
    Threadpool pool(5);
    for(int i = 0; i < 15; ++i) {
        pool.AddTask(test);
    }
    this_thread::sleep_for(10s); //等待15个线程执行完毕
}
[root@localhost 8]# g++ threadpool.cpp -pthread
[root@localhost 8]# ./a.out 
139998701491968:do something...
139998693099264:do something...
139998684706560:do something...
139998676313856:do something...
139998709884672:do something...
139998701491968:do something...
139998693099264:do something...
139998684706560:do something...
139998676313856:do something...
139998709884672:do something...
139998701491968:do something...
139998693099264:do something...
139998684706560:do something...
139998676313856:do something...
139998709884672:do something...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

九、Linux系统编程:线程池编程 的相关文章

  • C# SmtpClient编程中如何设置带有中文的附件文件名?

    我的代码如下 ContentType ct new ContentType ct MediaType MediaTypeNames Application Octet ct Name 这是一个很长的中文文件名希望能用它在附件名中 Doc A
  • 是否需要销毁运算符删除的形式才能真正销毁对象?

    C 20 添加了破坏形式operator delete区别于std destroying delete t范围 它导致delete表达式在调用之前不再销毁对象operator delete 目的是在显式调用对象的析构函数和释放内存之前 允许
  • 是否可以使用 http url 作为 DirectShow .Net 中源过滤器的源位置?

    我正在使用 DirectShow Net 库创建一个过滤器图 该过滤器图通过使用 http 地址和 WM Asf Writer 来流式传输视频 然后 在网页上 我可以使用对象元素在 Windows Media Player 对象中呈现视频源
  • 在 C++ 代码中转换字符串

    我正在学习 C 并开发一个项目来练习 但现在我想在代码中转换一个变量 字符串 就像这样 用户有一个包含 C 代码的文件 但我希望我的程序读取该文件并插入将其写入代码中 如下所示 include
  • 混合模型优先和代码优先

    我们使用模型优先方法创建了一个 Web 应用程序 一名新开发人员进入该项目 并使用代码优先方法 使用数据库文件 创建了一个新的自定义模型 这 这是代码第一个数据库上下文 namespace WVITDB DAL public class D
  • 如何向 Mono.ZeroConf 注册服务?

    我正在尝试测试 ZeroConf 示例http www mono project com Mono Zeroconf http www mono project com Mono Zeroconf 我正在运行 OpenSuse 11 和 M
  • 用于在标头更改时重新编译的简单 C 项目的示例 makefile

    有谁有完整的 makefile 可以执行以下操作 如果 HEADER 文件发生更改 则重建项目 cpp 文件在 makefile 中列出 头文件未在 makefile 中列出 头文件允许与 cpp 文件具有不同的名称 部分cpp文件没有头文
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • C# 根据当前日期传递日期时间值

    我正在尝试根据 sql server 中的两个日期获取记录 Select from table where CreatedDate between StartDate and EndDate我通过了5 12 2010 and 5 12 20
  • Linux 上的 RTLD_LOCAL 和dynamic_cast

    我们有一个由应用程序中的一些共享库构成的插件 我们需要在应用程序运行时更新它 出于性能原因 我们在卸载旧插件之前加载并开始使用新插件 并且只有当所有线程都使用旧插件完成后 我们才卸载它 由于新插件和旧插件的库具有相同的符号 我们dlopen
  • 来自嵌入图像的 BitmapSource

    我的目标是在 WPF 窗口上重写 OnRender 方法中绘制图像 someImage png 它是嵌入资源 protected override void OnRender System Windows Media DrawingCont
  • 测量进程消耗的 CPU 时钟

    我用 C 语言编写了一个程序 它是作为研究结果创建的程序 我想计算程序消耗的确切 CPU 周期 精确的循环次数 知道我怎样才能找到它吗 The valgrind tool cachegrind valgrind tool cachegrin
  • 如何防止 Blazor NavLink 组件的默认导航

    从 Blazor 3 1 Preview 2 开始 应该可以防止默认导航行为 https devblogs microsoft com aspnet asp net core updates in net core 3 1 preview
  • 在 azure blob 存储中就地创建 zip 文件

    我将文件存储在 Blob 存储帐户内的一个容器中 我需要在第二个容器中创建一个 zip 文件 其中包含第一个容器中的文件 我有一个使用辅助角色和 DotNetZip 工作的解决方案 但由于 zip 文件的大小最终可能达到 1GB 我担心在进
  • 如何从 Boost.PropertyTree 复制子树

    我有一些boost property tree ptree 我需要树来删除一些具有特定标签名称的元素 例如 xml 表示源ptree如下
  • 在哪里可以找到 Microsoft.Build.Utilities.v3.5

    如何获取 Microsoft Build Utilities v3 5 我正在使用 StyleCop 4 7 Stylecop dll 中的 StyleCop msbuild 任务似乎依赖于 Microsoft Build Utilitie
  • 如何高效计算连续数的数字积?

    我正在尝试计算数字序列中每个数字的数字乘积 例如 21 22 23 98 99 将会 2 4 6 72 81 为了降低复杂性 我只会考虑 连续的数字 http simple wikipedia org wiki Consecutive in
  • winform c# 中的弹出窗口

    我正在开发一个需要弹出窗口的项目 但问题是我还希望能够通过表单设计器在此弹出窗口中添加文本框等 所以基本上我有一个按钮 当您单击它时 它将打开我在表单设计器中设计的另一个窗口 我一直在谷歌搜索 但还没有找到我需要的东西 所以我希望你们能帮助
  • .Net Reactive Extensions Framework (Rx) 是否考虑拓扑顺序?

    Net 反应式扩展框架是否按拓扑顺序传播通知以最大限度地减少更新量 就像 Scala Rx 所做的那样 Net 反应式扩展 Rx 是否可以 https github com lihaoyi scala rx wiki How it Work
  • 从后面的代码添加外部 css 文件

    我有一个 CSS 文件 例如 SomeStyle css 我是否可以将此样式表文档从其代码隐藏应用到 aspx 页面 您可以将文字控件添加到标头控件中 Page Header Controls Add new System Web UI L

随机推荐

  • C++11之右值引用

    C 11之右值引用 传统的C 语法中就有引用的语法 而C 11中新增了的 右值引用 rvalue reference 语法特性 所以从现在开始我们之前学习的引用就叫做左值引用 lvalue reference 无论左值引用还是右值引用 都是
  • 东北大学c++实验第七周

    问题描述 分别声明Teacher 教师 类和Cadre 干部 类 采用多重继承方式由这两个类派生出新类Teacher Cadre 教师兼干部 类 要求 1 在两个基类中都包含姓名 年龄 性别 地址 电话等数据成员 2 在Teacher类中还
  • C++实现的自动构造LL(1)文法的first集、follow集和预测分析表。

    qquad 要求 程序识别的文法需是LL 1 文法 具体输入格式说明见initGrammer 本例采用的文法如下
  • 硬件工程师笔试题——21大疆秋招

    给志同道合者 成长的方向 鄙人不才 答案有误 三思 三思
  • Flask配置MySQL数据库使用

    文章目录 一 创建Flask 二 安装sqlalchemy 三 创建配置文件config py 四 绑定配置文件 参考资料 一 创建Flask pip install flask 成功安装之后app py如下所示 from flask im
  • python常用算法题-python基本算法题(一)

    1 3位水仙花数计算 3位水仙花数 是指一个三位整数 其各位数字的3次方和等于该数本身 例如 ABC是一个 3位水仙花数 则 A的3次方 B的3次方 C的3次方 ABC 使用Python 输出所有的3位水仙花数 gt gt gt for i
  • 匹配中文的正则表达式

    u4e00 u9fa5 匹配中文 匹配注释 不严密
  • hexo配置GitHub/gitee双部署

    我的博客主页 https qingmuzhang gitee io GitHub作为国外站点实在是比较慢也不太稳定 所以决定把博客搬到国内的gitee上 提高访问速度 gitee创建仓库 1 首先登录gitee https gitee co
  • matlab做三次拉格朗日插值多项式_拉格朗日插值法函数使用问题

    拉格朗日差值法 在数值分析中 拉格朗日插值法是以法国十八世纪数学家约瑟夫 拉格朗日命名的一种多项式插值方法 概念一般地 若已知 在互不相同 n 1 个点 处的函数值 即该函数过 这n 1个点 则可以考虑构造一个过这n 1 个点的 次数不超过
  • MLX90614红外温度计介绍

    MLX90614红外温度计简介 MLX90614是一款红外非接触温度计 TO 39金属封装里同时集成了红外感应热电堆探测器芯片和信号处理专用集成芯片 由于集成了低噪声放大器 17位模数转换器和强大的数字信号处理单元 使得高精度和高分辨度的温
  • 使用Stream流对集合排序

    文章目录 0 写在前面 1 格式 1 1 介绍 1 2 单个属性排序格式 1 3 多个属性排序格式 1 4 注意事项 2 代码举例 0 写在前面 有一些业务需要对集合按照一些规则进行排序 本篇介绍如何用Stream 对集合进行升序或者降序操
  • 学python可以做什么副业-写代码做副业月入10K的方法都藏在这几个公众号里!

    同为程序员 为什么总有人比你优秀 优秀的人是抱团的 因此 还不快关注这些优秀的公众号 学习技术 汲取他们的理念 化为己用 Python 爱好者社区 python shequ 简介 Python 爱好者社区 这里有分类整理好的历史优秀文章数千
  • Altium Designer多图纸原理图关联设计方法

    文章转载 http articles e works net cn eda article86269 htm 图纸结构 包括层次式图纸的连接关系是纵向的 也就是某一层次的图纸只能和相邻的上级或下级有关系 另一种即扁平式图纸的连接关系是横向的
  • 尚硅谷_vue核心基础部分

    01 初始vue 1 想让vue工作 就必须创建一个Vue实例 且要传入一个配置对象 2 root容器里的代码依然符合html规范 只不过混入了一些特殊的Vue语法 3 root容器里的代码被称为 Vue模板 4 Vue实例和容器是一一对应
  • crmeb 标准版Window+phpstudy8安装教程(一)

    标准版Window phpstudy8安装教程 一 安装前配置 nginx mysql php7 3 4 一 安装集成环境 这里以phpstudy为例 下载PHPstudy8 0安装 记录安装的位置 D phpstudy pro 二 准备源
  • 阿里云修复 polkit pkexec 本地提权漏洞(CVE-2021-4034)

    该漏洞EXP已公开传播 漏洞利用成本极低 建议您立即关注并修复 如何修复呢 解决建议 1 无法升级软件修复包的 可使用以下命令删除pkexec的SUID bit权限来规避漏洞风险 chmod 0755 usr bin pkexec 示例 l
  • maven野生仓库

    mvnrepository com
  • 洛谷借教室

    之前写过 再过一遍其实不会 题目描述 在大学期间 经常需要租借教室 大到院系举办活动 小到学习小组自习讨论 都需要向学校申请借教室 教室的大小功能不同 借教室人的身份不同 借教室的手续也不一样 面对海量租借教室的信息 我们自然希望编程解决这
  • linux服务器桌面卡死,linux服务器显卡崩溃解决方案

    在登录界面出现分辨率特别大 整个图形界面特别大 并且怎么也登录不上去的情况时 对于这种情况 一般就是显卡驱动崩了的原因 所以我们可以首先检查显卡驱动是否有问题 nvidia smi 如果出现说驱动链接不上什么的问题 就是说明你的显卡驱动出现
  • 九、Linux系统编程:线程池编程

    9 线程池编程 创建线程要花费昂贵的资源和时间 如果任务来了才创建线程那么响应时间会变长 而且一个进程能创建的线程数有限 为了避免这些问题 在程序启动的时候就创建若干线程来响应处理 它们被称为线程池 里面的线程叫工作线程 9 1 概念 线程