Linux 线程池的概念与实现

线程池概念:一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。

应用场景:1、需要大量的线程来完成任务,且完成任务的时间比较短;2、对性能要求苛刻的应用;3、接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用
不使用线程池的情况:若是一个数据请求的到来伴随一个线程去创建,就会产生一定的风险以及一些不必要的消耗。
1、线程若不限制数量的创建,在峰值压力下,线程创建过多,资源耗尽,有程序崩溃的风险;
2、处理一个短时间任务时,会有大量的资源用于线程的创建与销毁成本上。
功能:线程池是使用了已经创建好的线程进行循环处理任务,避免了大量线程的频繁创建与销毁的时间成本

如何实现一个线程池

线程池 = 大量线程 + 任务缓冲队列

困难与解决方案:在创建线程时,都是伴随创建线程的入口函数,一旦创建就无法改变,导致线程池进行任务处理的方式过于单一,灵活性太差。若任务队列中的任务,不仅仅是单纯的数据,而是包含处理任务方法在内的数据,这时候,线程池的线程是一条普通的执行流,只需要使用传入的方法去处理数据即可。这样子就可以提高线程池的灵活性
在这里插入图片描述
代码实现流程:定义一个任务类Task,成员变量有要处理的数据_data和处理数据的方法_handler。成员函数有设置要处理数据和处理方式的函数setTask,还有一个处开始处理数据的函数run(创建线程时传入的方法,由于创建线程必须有入口函数,这里用run封装所有的处理方式,让所有线程都将run置为入口函数,就提高了线程池的灵活性)。再定义一个线程池类ThreadPool,成员变量有定义线程池中线程的最大数量thr_max,一个任务缓冲队列_queue,一个互斥量_mutex,用于实现对缓冲队列的安全性,一个条件变量_cond,用于实现线程池中线程的同步。

threadpool.hpp文件

//threadpool.hpp
#include <iostream>
#include <cstdio>
#include <queue>
#include <stdlib.h>
#include <pthread.h>
using namespace std;

typedef void (*handler_t)(int);
#define MAX_THREAD 5
//任务类
class ThreadTask
{
    public:
        ThreadTask()
        {

        }
        //将数据与处理方式打包在一起
        void setTask(int data, handler_t handler)
        {
            _data = data;
            _handler = handler;
        }
        //执行任务函数
        void run()
        {
            return _handler(_data);
        }
    private:
        int _data;//任务中处理的数据
        handler_t _handler;//处理任务方式
};

//线程池类
class ThreadPool
{
    public:
        ThreadPool(int thr_max = MAX_THREAD)
            :_thr_max(thr_max)
        {
            pthread_mutex_init(&_mutex, NULL);
            pthread_cond_init(&_cond, NULL);
            for (int i = 0; i < _thr_max; i++)
            {
                pthread_t tid;
                int ret = pthread_create(&tid, NULL, thr_start, this);
                if (ret != 0)
                {
                    printf("thread create error\n");
                    exit(-1);
                }
            }
        }
        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }
        bool taskPush(ThreadTask &task)
        {
            pthread_mutex_lock(&_mutex);
            _queue.push(task);
            pthread_mutex_unlock(&_mutex);
            pthread_cond_signal(&_cond);
            return true;
        }
        //类的成员函数,有默认的隐藏参数this指针
        //置为static,没有this指针,
        static void *thr_start(void *arg)
        {
            ThreadPool *p = (ThreadPool*)arg;
            while (1)
            {
                pthread_mutex_lock(&p->_mutex);
                while (p->_queue.empty())
                {
                    pthread_cond_wait(&p->_cond, &p->_mutex);
                }
                ThreadTask task;
                task =p-> _queue.front();
                p->_queue.pop();
                pthread_mutex_unlock(&p->_mutex);
                task.run();//任务的处理要放在解锁之外
            }
            return NULL;
        }
    private:
        int _thr_max;//线程池中线程的最大数量
        queue<ThreadTask> _queue;//任务缓冲队列
        pthread_mutex_t _mutex; //保护队列操作的互斥量
        pthread_cond_t _cond; //实现从队列中获取结点的同步条件变量
};

main.cpp

//main.cpp
#include <unistd.h>
#include "threadpool.hpp"

//处理方法1
void test_func(int data)
{
    int sec = (data % 3) +1;
    printf("tid:%p -- get data:%d, sleep:%d\n", pthread_self(), data, sec);
    sleep(sec);
}

//处理方法2
void tmp_func(int data)
{
    printf("tid:%p -- tmp_func\n", pthread_self());
    sleep(1);
}

int main()
{
    ThreadPool pool;
    for (int i = 0; i < 10; i++)
    {
        ThreadTask task;
        if (i % 2 == 0)
        {
            task.setTask(i, test_func);
        }
        else
        {
            task.setTask(i, tmp_func);
        }
        pool.taskPush(task);
    }
    sleep(1000);
    return 0;
}

运行结果:线程池最多有5个线程,标注的每种颜色对应的是同一个线程,这样子就能完成通过几个线程,完成多个任务,而不是多个线程完成多个任务。创建和销毁的时间开销也节省了不少
在这里插入图片描述

  • 18
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
在C语言中实现一个简单的线程池可以按照以下步骤进行: 1. 定义线程池结构体:创建一个结构体,包含线程池中的线程数量、任务队列、互斥锁、条件变量等必要的成员。 ```c typedef struct { pthread_t *threads; // 线程数组 int thread_count; // 线程数量 task_queue_t *task_queue; // 任务队列 pthread_mutex_t mutex; // 互斥锁 pthread_cond_t cond; // 条件变量 int shutdown; // 线程池关闭标志 } thread_pool_t; ``` 2. 定义任务队列结构体:创建一个结构体,用于存储任务队列的信息,包括任务数组、任务数量、头尾指针等成员。 ```c typedef struct { task_t **tasks; // 任务数组 int task_count; // 任务数量 int head; // 队列头指针 int tail; // 队列尾指针 } task_queue_t; ``` 3. 定义任务结构体:创建一个结构体,用于存储具体的任务信息,例如任务函数指针和参数。 ```c typedef struct { void (*function)(void *); // 任务函数指针 void *argument; // 任务参数 } task_t; ``` 4. 初始化线程池:创建线程池,并初始化线程数组、任务队列、互斥锁、条件变量等。 5. 添加任务:将任务添加到任务队列中,并通过条件变量通知线程池中的线程有新任务可执行。 6. 线程函数:线程池中的线程函数,循环从任务队列中取出任务并执行。 7. 等待线程池任务完成:可以通过条件变量等待所有任务执行完毕。 8. 销毁线程池:释放线程池中的资源,包括线程数组、任务队列、互斥锁、条件变量等。 这是一个简单的线程池实现的框架,你可以根据自己的需求进行具体的功能扩展和优化。注意在并发环境中使用互斥锁和条件变量来保证线程安全。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WhiteShirtI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值