【Linux】—— 线程池的概念及实现

前面我们介绍了线程相关的所有概念,根据之前的所学的概念,接着我们看一下下面这张图

  • 线程生命周期,一个线程从生到死的过程
    线程的生命周期

线程池

以上介绍我们可以看出,在一个应用程序中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存。而在C++中,内存资源是及其宝贵的,计算机的大佬们就提出了线程池的概念。

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

线程池的应用场景

  • 需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。 但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
  • 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
  • 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,出现错误。

四种常见的线程池

  • CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。
  • SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。
  • SingleThreadPool:只有一条线程来执行任务,适用于有顺序的任务的应用场景。
  • FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程

C++编写一个线程池

该线程池可以完成简单的计算器功能,加减乘除等,该线程池暂时设置的是5个线程可同时执行计算结果。

  • threadpool.hpp
#ifndef __THREADPOOL_HPP__
#define __THREADPOOL_HPP__

#include <iostream>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <queue>
#include <unistd.h>
using namespace std;

typedef int (*HandlerTask_t)(int x,int y,int op);
class Task{
    private:
        int x;
        int y;
        char op; //0+,1-,2*,3/
        HandlerTask_t handler;
    public:
        Task(int x_ = -1,int y_ = -1,int op_ = -1)
            :x(x_),y(y_),op(op_)
        {

        }
        void Register(HandlerTask_t handler_)
        {
            handler = handler_;
        }

        void Run()
        {
            int res = handler(x,y,op);
            const char* op_ = "+-*/";
            cout << "thread:[ "<<pthread_self() << " ]"<< " handler reslut:";
            cout << x << op_[op] << y << " = " << res << endl;
        }

        ~Task()
        {}
};

class ThreadPool{
    private:
        int thread_nums;
        int idle_nums;
        queue<Task> task_queue;
        pthread_mutex_t lock;
        pthread_cond_t cond;
    public:
        void LockQueue()
        {
            pthread_mutex_lock(&lock);
        }
        void UnlockQueue()
        {
            pthread_mutex_unlock(&lock);
        }
        bool QueueIsEmpty()
        {
            return task_queue.size() == 0;
        }
        void ThreadIdle()
        {
            idle_nums++;
            pthread_cond_wait(&cond,&lock);
            idle_nums--;
        }
        void WakeupThread()
        {
            idle_nums--;
            pthread_cond_signal(&cond);
            idle_nums++;
        }
        void PopTask(Task& t)
        {
            t = task_queue.front();
            task_queue.pop();
        }
    public:
        ThreadPool(int num_ = 5):thread_nums(num_),idle_nums(0)
        {
            pthread_mutex_init(&lock,NULL);
            pthread_cond_init(&cond,NULL);
        }

        static void* ThreadRotinue(void* arg)
        {
            pthread_detach(pthread_self());
            ThreadPool *tp = (ThreadPool*)arg;
            for(;;){
                tp->LockQueue();
                while(tp->QueueIsEmpty()){
                   tp->ThreadIdle();
                }
                Task t;
                tp->PopTask(t);
                //Task t = task_queue.front();
                //task_queue.pop();
                tp->UnlockQueue();
                t.Run();
            }
        }

        void InitThreadPool()
        {
            pthread_t t;
            for(auto i = 0; i < thread_nums;i++){
                pthread_create(&t,NULL,ThreadRotinue,this);
            }

        }
        
        void PushTask(const Task &t)
        {
            LockQueue();
            task_queue.push(t);
            WakeupThread();
            UnlockQueue();
        }
        ~ThreadPool()
        {
            pthread_mutex_destroy(&lock);
            pthread_cond_destroy(&cond);
        }

};
#endif
#include "threadpool.hpp"

int cal(int x,int y,int op)
{
    int ret = -1;
    switch(op)
    {
        case 0:
            ret = x + y;
            break;
        case 1:
            ret = x - y;
            break;
        case 2:
            ret = x * y;
            break;
        case 3:
            ret = x / y;
            break;
        default:
            cout << "cal error!" << endl;
            break;
    }
}

int main()
{
    ThreadPool tp;
    tp.InitThreadPool();
    srand((unsigned long)time(NULL));
    for(;;){
        sleep(1);
        int x = rand() % 100 + 1;
        int y = rand() % 100 + 1;
        int op = rand() % 4;
        Task t(x,y,op);
        t.Register(cal);

        tp.PushTask(t);
    }
    return 0;
}
  • Makefile
threadpool:threadpool.cc
	g++ -std=c++11 -o $@ $^ -lpthread
.PHONY:clean
clean:
	rm -f threadpool
发布了167 篇原创文章 · 获赞 175 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/chenxiyuehh/article/details/98038292