【Linux】线程池(C++实现)

线程池

一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。
A.降低资源消耗:通过重用已经创建的线程来降低线程创建和销毁的消耗
B.提高线程的可管理性:线程池可以统一管理、分配、调优和监控
C.程序性能更优:创建的线程越多性能越高

实现一个线程池

在这里插入图片描述
先封装一个待处理的数据和处理数据的函数 class Task

typedef void (*handler_t)(int data);
class Task {
private:
    int _data;
    handler_t _handler;
public:
    void setdata(int data, handler_t func) {
        _data = data;
        _handler = func;
    }
    void run() {
        _handler(_data);
    }
};
void thr_handle(int data) {
    srand(time(NULL));
    int sec = rand() % 5;
    printf("thr:%p--get data:%d--sleep:%d sec\n", pthread_self(), data, sec);
    sleep(sec);
}

实现一个线程池:由一个线程安全的任务队列和多个线程组成
有一个问题需要注意的是:线程什么时候退出?
  如果主函数退出的话,则可能有线程还没没有处理完就退了,所以需要所有线程全部退出后主线程才可以退出。
  这时增加两个成员变量,一个记录正在处理任务的线程的个数,一个是状态标志位(区分线程被唤醒是否被退出函数唤醒的)
  线程池收到退出请求,将退出标志位设置为true,判断是否还有线程运行,在去唤醒所有线程,如果有线程被唤醒说明,这个线程已经没有在处理任务,则将该线程退出。

class ThreadPool {
private:
    int th_max;
    std::queue<Task> _task_queue;
    pthread_mutex_t mutex;
    pthread_cond_t pro_cond;
    pthread_cond_t con_cond;
    int _cur_thr; //当前线程数
    bool _quit_flag;  //线程池中线程退出标志
    
private:
    void QueueBlock() {
        pthread_mutex_lock(&mutex);
    }
    void QueueUnBlock() {
        pthread_mutex_unlock(&mutex);
    }
    void ConsumerWait() {
        //线程陷入等待之前先判断一下用户是否要销毁线程池
        if (_quit_flag == true) {
        	_cur_thr--;
        	pthread_mutex_unlock(&mutex);
        	printf("thread:%p exit\n", pthread_self());
        	pthread_exit(NULL);
        }
        pthread_cond_wait(&con_cond, &mutex);
    }
    void ConsumerWakeUp() {
        pthread_cond_signal(&con_cond);
    }
    void ConsumerWakeUpAll() {
        pthread_cond_broadcast(&con_cond);
    }
    bool QueueIsEmpty() {
        return _task_queue.empty();
    }
    
public:
    ThreadPool(int max = THR_MAX) : th_max(max), _cur_thr(max) {
        _quit_flag = false;
        pthread_mutex_init(&mutex, NULL);
        pthread_cond_init(&con_cond, NULL);
        pthread_cond_init(&pro_cond, NULL);
    }

    ~ThreadPool() {
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&con_cond);
        pthread_cond_destroy(&pro_cond);
    }

    bool PoolInit() {
        int ret;
        pthread_t tid;
        for (int i = 0; i < th_max; ++i) {
      	    ret = pthread_create(&tid, NULL, thr_start, this);
      	    if (ret != 0) {
          		std::cout << "pthread create error\n";
          		return false;
        	}
           	pthread_detach(tid);
        }
        return true;
    }

    bool TaskPush(Task &t) {
        pthread_mutex_lock(&mutex);
        _task_queue.push(t);
        pthread_cond_signal(&con_cond);
        pthread_mutex_unlock(&mutex);
        return true;
    }

    bool TaskPop(Task &t) {
        t = _task_queue.front();
        _task_queue.pop();
        return true;
    }

    //static原因:如果不是static,这个函数还有一个默认参数this,这个函数就不能做创建进程函数的参数了
    static void* thr_start(void* arg) {
        ThreadPool* pool = (ThreadPool*)arg;
        while (1) {
        	pthread_mutex_lock(&pool->mutex);
        	while (pool->_task_queue.empty()) {
          		pool->ConsumerWait();
        	}
        	Task t;
        	pool->TaskPop(t);
        	pthread_mutex_unlock(&pool->mutex);
        	t.run();
        }
        return NULL;
    }

    //为了避免主函数退出,导致所有线程退出, 让所有线程处理完再退出
    void PoolQuit() {
        QueueBlock();
        if (_quit_flag == false) {
        	_quit_flag = true;
        }
        QueueUnBlock();
        while (_cur_thr > 0) {
        	ConsumerWakeUpAll();
        	usleep(1000);
        }
    }
};

int main() {
    ThreadPool pool;
    pool.PoolInit();
    for (int i = 0; i < 10; ++i) {
    	Task* task = new Task();
    	task->setdata(i, thr_handle);
    	pool.TaskPush(*task);
    }
    pool.PoolQuit();
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值