WD1X.COM - 问答一下,轻松解决,电脑应用解决专家
主板显卡CPU内存显示器
硬盘维修显卡维修显示器维修
系统注册表系统命令DOSWin8
存储光存储键盘鼠标
内存维修打印机维修
WinXPVistaWin7linux
硬件综合机箱电源/散热器手机数码
主板维修CPU维修键鼠维修网页设计
办公教程ExcelWordPowerPointWPS
网络工具系统工具图像工具
PS教程数据库局域网服务器
PHP教程CSSjavascriptXML

Linux 线程池的概念与实现

更新时间:2021-04-11 14:13 作者:WhiteShirtI点击:
应用场景:

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个线程,标注的每种颜色对应的是同一个线程,这样子就能完成通过几个线程,完成多个任务,而不是多个线程完成多个任务。创建和销毁的时间开销也节省了不少
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
你可能感兴趣的内容