为什么需要线程池
在那些情况下我们会使用到多线程:
阻塞调用(阻塞IO调用、等待资源)
耗时的计算(读写文件、复杂的计算)
高密度任务(高并发低延时的网络IO请求)
面临以上情况时都去临时创建线程会带来什么问题:
创建了太多的线程,系统资源就会被浪费,而且会浪费时间去创建和销毁线程。
创建线程太慢,导致执行任务结果返回过慢。
销毁线程太慢,可能会影响别的进程使用资源。
所以:创建多个线程,放在池子里不销毁,要用的时候就把任务丢给池子里的线程去执行,这就是线程池。
OK,问题来了任务由谁产生(生产者),如何丢给线程池的某个线程(消费者)?这个问题的回答需从以下几方面:
1) 生产者采用什么方式与消费者同步?
2) 任务如何保存?
3) 生产者之间的同步方式,消费者之间的同步方式?
一下所有的代码设计适用于单生产者多消费者模式
条件变量结合互斥锁 + 任务队列
设计如何:
代码如下:
typedef struct queue_task
{
void* (*run)(void *);
void* argv;
}task_t;
typedef struct queue
{
int head;
int tail;
int size;
int capcity;
task_t* tasks;
} queue_t;
typedef struct async_queue
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int waiting_threads;
queue_t* queue;
int quit; // 0 表示不退出 1 表示退出
/* 调试变量 */
long long tasked; // 已经处理完的任务数量
} async_queue_t;
取任务的代码设计如下:
task_t* async_cond_queue_pop_head(async_queue_t* q, int timeout)
{
task_t *task = NULL;
struct timeval now;
struct timespec outtime;
pthread_mutex_lock(&(q->mutex));
if (queue_is_empty(q->queue))
{
q->waiting_threads++;
while (queue_is_empty(q->queue) && (q->