手把手教你写Linux线程池

news2024/11/27 6:28:23

手把手教你写Linux线程池

如果需要线程池源码,关注Linux兵工厂,并由大量Linux资料赠送。

线程池

顾名思义,存储线程的池子。线程池是线程的一种使用模式。在平常业务开发中常规的逻辑是遇到任务然后创建线程去执行。但是线程的频繁创建就类似于内存的频繁申请和销毁,会给操作系统带来大的压力,进而影响整体的性能。所以我们一次申请好一定数量而定线程,然后将线程的管理操作交给线程池,就避免了在短时间内不断创建与销毁线程的代价,线程池不但能够保证内核的充分利用,还能防止过分调度,并根据实际业务情况进行修改。

使用线程池的好处

  • 任务到来后立马就有线程去执行任务,节省了创建线程的时间
  • 防止服务器线程过多导致的系统过载问题
  • 相对于进程池,线程池资源占用较少,但是健壮性很差
  • 降低资源消耗,通过重用已经创建的线程来降低线程创建和销毁的消耗
  • 提高线程的可管理性,线程池可以统一管理、分配、调优和监控其中的线程

什么情况下使用线程池

  • 需要大量的线程来完成任务,且完成任务的时间比较短
  • 对性能要求苛刻的应用
  • 接收突发性的大量请求,但不至于使服务器因此产生大量线程的应用

线程不是越多越好

线程的越多,可能会导致线程切换越频繁, 进而还有可能导致程序运行效率降低。多线程程序的运行效率, 是一个正态分布的结果, 线程数量从1开始增加, 随着线程数量的增加, 程序的运行效率逐渐变高, 直到线程数量达到一个临界值, 再次增加线程数量时, 程序的运行效率会减小(主要是由于频繁的线程切换影响线程运行效率)。

  • 线程若不限制数量的创建,线程创建过多,资源耗尽,有程序崩溃的风险
  • 处理一个短时间任务时,线程会频繁创建和销毁,占用系统资源,降低系统性能

Linux如何实现一个线程池

  • 每个任务在放入任务队列时设置好需要处理的数据和处理函数
  • 线程池中的线程负责从任务队列当中获取任务,并进行处理
    在这里插入图片描述

代码实现过程

  • 创建一个任务类CTask,可以设置处理任务的回调func以及需要处理的数据m_data
  • 创建一个线程池类CThreadPool,成员变量有设置线程池中线程的最大数量thr_max,任务缓冲队列m_queue,互斥量m_mutex,用于实现对缓冲队列的安全性,条件变量m_cond,用于实现线程池中线程的同步

创建任务类

/* 任务类 */
class CTask
{
public:
    CTask(){}
    ~CTask(){}

    void SetTask(int data, func handler) // 设置数据和处理接口
    {
        m_data = data;
        m_handler = handler;
    }
    
    void Do() // 执行任务
    {
        return m_handler(m_data);
    }

private:
    int  m_data;     // 数据
    func m_handler;  // 处理接口
};

创建线程池类

    1. 创建线程池
    /* 创建线程池 */
    for (int i = 0; i < m_SumMax; i++)
    {
        pthread_t tid;
        int ret = pthread_create(&tid, NULL, ThrPoolRun, this);
        if (ret != 0)
        {
            printf("thread create error\n");
        }
    }
    1. 任务放入队列
    bool TaskPush(CTask &task)
    {
        pthread_mutex_lock(&m_Mutex);
        m_Queue.push(task);
        pthread_mutex_unlock(&m_Mutex);
        pthread_cond_signal(&m_Mond);
        return true;
    }
    1. 线程池空闲线程从队列获取任务并处理
    CThreadPool *p = (CThreadPool*)arg;

    while (p->m_bIsRun)
    {
        pthread_mutex_lock(&p->m_Mutex);

        /* 等待任务到来 */
        while (p->m_Queue.empty())
        {
            pthread_cond_wait(&p->m_Mond, &p->m_Mutex);
        }

        /* 取出任务 */
        CTask Task;
        Task =p->m_Queue.front();
        p->m_Queue.pop();
        pthread_mutex_unlock(&p->m_Mutex);

        /* 处理任务 */
        Task.Do();
    }

main函数

void TaskFunc1(int nData)
{
    printf("TaskFunc1, ThreadId: %p, nData:%d\n", pthread_self(), nData);

    sleep(1);
}

void TaskFunc2(int nData)
{
    printf("TaskFunc2, ThreadId: %p, nData:%d\n", pthread_self(), nData);

    sleep(1);
}

int main(int argc, char const *argv[])
{
    CThreadPool ThreadPool;

    for (size_t i = 0; i < 10; i++)
    {
        CTask Task;

        (0 == (i % 2)) ? Task.SetTask(i, TaskFunc1) : Task.SetTask(i, TaskFunc2);

        ThreadPool.TaskPush(Task);  // 放入任务队列
    }
    
    sleep(3);
    return 0;
}

运行结果

  • 10个任务被5个线程分别处理完
    1

总结

至此,一个简单的线程池实例就完成了。实际工作中我们可以根据实际的业务量来初始化线程池中线程的个数,并根据任务量的多少动态的增加或减少线程池中的线程。好了,现在让我们行动起来吧,自己编写一个线程池。

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

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

相关文章

NR小区搜索(五)S准则

微信同步更新欢迎关注同名modem协议笔记 UE根据支持的频段进行小区搜索过程&#xff0c;检测PSS/SSS->PBCH&#xff0c;然后就可以读到MIB&#xff0c;根据MIB中的pdcch-ConfigSIB1&#xff0c;可以找到CORESET0 和SearchSpace0的信息&#xff0c;进而可以确定一块时频域资…

软件测试 -- 进阶 6 软件缺陷

上工治未病之病&#xff0c;中工治欲病之病&#xff0c;下工治已病之病。-- 孙思邈 .《千金方药方》 释译&#xff1a;未病之病&#xff1a;未病&#xff0c;未发之病&#xff08;及早干预&#xff0c;防止病发&#xff09;&#xff1b;欲病之病&#xff1a;小病&#xff0…

MIR7创建预制发票BAPI

1、事务代码MIR7 前台输入采购订单等相关字段进行开票 2、代码实现 调用BAPI&#xff1a;BAPI_INCOMINGINVOICE_PARK创建发票 "--------------------斌将军-------------------- DATA:ls_headerdata TYPE bapi_incinv_create_header,lv_invoicedocnumber LIKE ba…

桌面画图工具:Pointofix(fertig)

Pointofix桌面画图工具 Pointofix - der virtuelle Textmarker fr Ihren Bildschirm - Freeware 一、软件下载 官方网址https://www.pointofix.de/ 二、进入下载页面&#xff0c;需要下载安装文件和语言包两个文件 三、网站还提供了一个语言设置小程序&#xff0c;但我没用 …

JavaSE笔记——抽象类和接口

文章目录前言一、抽象类和方法二、接口创建1.默认方法2.多继承3.接口中的静态方法三、抽象类和接口四、完全解耦五、使用继承扩展接口六、接口适配七、接口字段八、接口和工厂方法模式总结前言 接口和抽象类提供了一种将接口与实现分离的更加结构化的方法。 一、抽象类和方法 …

传奇外网架设教程

外网架设前需准备&#xff1a; 准备工具:传奇版本源码&#xff0c;服务器&#xff0c;备案域名&#xff0c;DBC数据库&#xff0c;周年客户端 服务器和备案域名需要自备或者租用&#xff0c;这东西自己造不出来&#xff01;&#xff01;&#xff01; 其他的工具&#xff0c;…

Flink被阿里收购4年,最开心的却是Spark背后的Databricks

最近&#xff0c;Flink Forward Asia&#xff08;FFA&#xff09;峰会成功举行&#xff0c;有关Flink的讨论&#xff0c;又开始在国内热闹起来。 2022 年&#xff0c;Apache Flink 社区保持快速发展&#xff1a;GitHub Star 数突破 2 万&#xff0c;单月下载量突破 1400 万次&…

学习总结 | 下一代人工智能

文章目录 一、前言二、底层逻辑三、六大维度今后发展的方向是第三代人工智能,最主要的措施就是把第一代人工智能知识驱动的方法和第二代人工智能数据驱动的方法结合起来,发展安全、可信、可靠和可扩展的人工智能技术,从而推动人工智能的创新应用。 一、前言 中国科学院院士…

iTOP3A5000开发板多路PCIE、SATA、USB3.0等

iTOP3A5000开发板多路PCIE、SATA、USB3.0等 桥片&#xff1a;支持PCIE3.0、USB3.0、SATA3.0、显示接口2路、HDMI和1路VGA、可直接连显示器&#xff0c;另外内置一个网络PHY&#xff0c;片内集成了自研GPU、搭配32位DDR4显存接口&#xff0c;支持16GB显存容量。 底板引出多路PCI…

第3关:添加数据、删除数据、删除表

为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.如何使用HBase shell命令添加数据、2.如何使用命令删除表。 首先启动HBASE 启动HBASEshell 添加数据 我们来给上一关创建的test表的列data添加一些数据&#xff1a; hbase(main):002:0> create test,data Created t…

在 Python 中构建一体化音频分析工具包,在一个地方分析您的音频文件

语言构成了人类之间每次对话的基础。因此,自然语言处理(或简称 NLP)领域无疑在帮助人类日常生活方面具有巨大潜力。 简而言之,NLP 领域包含一组旨在理解人类语言数据并完成下游任务的技术。 NLP 技术涵盖许多领域,例如问答 (QA)、命名实体识别 (NER)、文本摘要、自然语言…

0111 栈与队列Day1

剑指offer09.用两个栈实现队列 用两个栈实现一个队列。队列的声明如下&#xff0c;请实现它的两个函数 appendTail 和 deleteHead &#xff0c;分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素&#xff0c;deleteHead 操作返回 -1 ) 示例 1&#x…

音视频开发入门小知识

什么是视频 视频就是由一系列图片构成的&#xff0c;当画面快速切换时&#xff0c;人眼看起来就感觉是连贯的动作。 视频帧 帧&#xff0c;表示一张画面&#xff0c;就是一帧。一个视频就是由许许多多帧组成的。 帧率 帧率&#xff0c;表示单位时间内帧的数量&#xff0c;…

KingbaseES数据库 kdb_schedule 自动定时任务

KingbaseES数据库 kdb_schedule 自动定时任务 文章目录KingbaseES数据库 kdb_schedule 自动定时任务前言一 安装插件 kdb_schedule1. 添加kdb_schedule2. 修改kdb_schedule所需参数&#xff1a;3. 重启数据库4. 加载kdb_schedule插件二 dbms_scheduler2.1 创建program创建progr…

(四) 共享模型之管程【Monitor 概念】

一、Java 对象头&#xff08;P75&#xff09; 二、原理之 Monitor(锁) Monitor 被翻译为监视器或管程。 每个 Java 对象都可以关联一个 Monitor 对象&#xff0c;如果使用 synchronized 给对象上锁&#xff08;重量级&#xff09;之后&#xff0c;该对象头的 Mark Word 中就被设…

Cookie Session JSP

这里写目录标题1 Cookie1.1 会话介绍1.2 Cookie 介绍1.3 Cookie 属性1.4 Cookie 方法1.4.1 Cookie 添加和获取1.5 Cookie 的使用1.6 Cookie 的细节2 Session2.1 HttpSession 介绍2.2 HttpSession 常用方法2.3 HttpSession 获取2.4 HttpSession 的使用2.5 HttpSession 的细节3 J…

高压功率放大器在超声驻波声场的听声器中的应用

实验名称&#xff1a;高压功率放大器在超声驻波声场的听声器声压测量中的应用 研究方向&#xff1a;3D打印 测试目的&#xff1a;利用听声器对声场的测量是一种基于对声压的采集&#xff0c;利用CPB分析及FFT分析处理&#xff0c;得到涉入点声压的方法。介于听声器采集信号为时…

单字段纵向分栏

【问题】 Hi, I’m trying to display BIRT report Data (only one field) first vertically till the page ends and then it should continue in the next column of the same page. For example as A E I B F J C G D HBy using list element I’m able to get the data …

opencv上设置摄像头曝光参数的经验

实际应用中我们需要调整摄像头的参数比如曝光&#xff0c;由于opencv的后端是一般编译是支撑多种插件&#xff0c;详细信息请参考OpenCV: Video I/O with OpenCV Overview&#xff0c;这里引用里面的图&#xff1a; 对于VideoCaputure&#xff0c;后端有ffmpge&#xff0c;V4L&…

SpringMVC入门

SpringMVC 一、SpringMVC简介 1、什么是MVC MVC是一种软件架构的思想&#xff0c;将软件按照模型、视图、控制器来划分 M&#xff1a;Model&#xff0c;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据 JavaBean分为两类&#xff1a; 一类称为实体类Bea…