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个线程,标注的每种颜色对应的是同一个线程,这样子就能完成通过几个线程,完成多个任务,而不是多个线程完成多个任务。创建和销毁的时间开销也节省了不少
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_44443986/article/details/115441456
今日推荐