线程池 简介

1. 什么是线程池?

在多线程程序中,如果频繁创建和销毁线程,成本会非常高。预先创建部分线程,这些线程的集合叫做线程池。这样,程序讲任务传递给线程池,线程池就启动一个线程来处理任务,任务结束之后,线程置于空闲状态,等待下一个任务,这样可以很好的提高性能。

和普通的多线程相比主要有两点不同:

  1. 任务由线程池管理,线程池拿到任务之后,会安排空闲的线程进行处理,如果没有则等待。
  2. 线程池可以同时处理多个任务,一个线程同时只能执行一个任务

我们可以把线程理解成一个散工,一般情况下,比如我们家里需要粉刷墙,则到劳工市场找一个散工来做这件事,雇主和散工直接交互。而线程池可以理解成散工的“工会”,我们打电话给工头,他来分配工人即可,他掌握着“散工”资源,雇主和散工之间加了一个“工头”。

 

2. 线程池有什么用?

减少频繁创建和销毁线程所损耗的性能,降低成本。

预先分配一定的资源,减少创建和销毁的代价,类似的技术还有对象池、连接池等其他池化技术。

 

3. 如何使用线程池?

线程池是一项成熟的技术,像boost、poco等框架中都有支持。使用简单,如下poco使用线程池的简单例子。

    ThreadPool(int minCapacity = 2,

        int maxCapacity = 16,

        int idleTime = 60,

        int stackSize = POCO_THREAD_STACK_SIZE);

        /// Creates a thread pool with minCapacity threads.

        /// If required, up to maxCapacity threads are created

        /// a NoThreadAvailableException exception is thrown.

        /// If a thread is running idle for more than idleTime seconds,

        /// and more than minCapacity threads are running, the thread

        /// is killed. Threads are created with given stack size.

创建线程池时,一般会指定线程池最小线程数和最大线程数,空闲时间,线程栈大小等。

ThreadPool tp(8, 128, 120);

TaskManager* tm= new TaskManager(tp); //初始化任务管理器与线程池进行关联

tm->start(new Task());//开启一个线程

tm->cancelAll();

tm->joinAll();

或者

ThreadPool tp(8, 128, 120);

RunnableAdapter<ThreadPoolTest> ra(*this, &ThreadPoolTest::hello); 

tp.start(ra); 

 

如果要自己实现一个线程池,要了解以下几点

重点数据结构是什么?

首先线程池要有默认线程数量,程序启动时,默认开启固定数量的线程。

再者,线程池不可能无限制的增长,要有个最大线程数量

如果线程池空闲时间比较长,也应有一个空闲时间最小线程数量

还有如果任务多了,线程不够,需要增加x个;如果任务少了,线程要销毁x个,那么这个增减的步长也是线程池的属性之一。

 

管理者线程

工作线程的创建和销毁,管理线程的数量

任务队列

为了保证线程安全,必然包含 条件变量互斥锁

如果任务队列中有数据(任务)的话,激活堵塞在条件变量上的线程

如果任务队列满了怎么办?

  • 阻塞生产者往队列里扔数据

如果任务队列空了怎么办?

  • 阻塞消费者(线程池)从队列里取数据

struct threadpool_t {

// 保持线程安全

pthread_mutex_t lock; /* 结构体锁 */

pthread_mutex_t thread_counter; /* busy_thr_num锁 */

pthread_cond_t queue_not_full; /* 当任务队列满时,添加任务的线程阻塞,等待此条件变量 */

pthread_cond_t queue_not_empty; /* 任务队列里不为空时,通知等待任务的线程 */

 

pthread_t *threads; /* 线程数组 */

pthread_t adjust_tid; /* 管理线程*/

threadpool_task_t *task_queue; /* 任务队列 */

 

//数量

int min_thr_num; /* 最小线程数 */

int max_thr_num; /* 最大线程数 */

int live_thr_num; /* 存活线程个数 */

int busy_thr_num; /* 忙状态线程个数 */

int wait_exit_thr_num; /* 要销毁的线程个数 */

 

//队列信息

int queue_front; /* task_queue队头下标 */

int queue_rear; /* task_queue队尾下标 */

int queue_size; /* task_queue队中实际任务数 */

int queue_max_size; /* task_queue队列可容纳任务数上限 */

 

int shutdown; /* 标志位,线程池使用状态,true或false */

};

 

3.2 重要函数(实现)是什么?

  1. 创建线程池
    1. 分配线程池结构体空间,初始化参数
    2. 初始化任务队列
    3. 创建默认N个线程
  2. 工作线程处理
  • 线程处理函数死循环,循环内访问线程池,前后加解锁
  • 死循环,等待任务队列不为空的条件变量触发
  • 若触发则进行工作

   3.管理线程

  1. 死循环,去存活数量和忙碌数量
  2. 线程不够用的时候,创建线程
  3. 线程空闲的时候,销毁线程

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值