目录
1、线程池的基本思想
(1)减少线程的创建和销毁带来的内存的消耗。
(2)可以将主线程与其他无关工作任务异步解耦,由线程池去完成主线程无关的工作,如 记录日志的任务就可以抛入线程池去执行。也可以异步处理耗时的操作
(3)线程池的基本思想,来源于 工作者 和 任务。 工作者不断从任务队列取任务执行,主线程则不断往工作队列中加入新的执行任务。
2、线程池的进阶想法
(1)可以创建多个线程池,不同线程池执行不同类别的任务,或者可以通过多个线程池,完成对任务优先级的划分。
(2)对于 计算密集型(CPU经常参与的) 以及 任务密集型(重IO操作的,经常等待的),线程池可以创建不同数量的线程个数。
(3)可以根据 执行任务加减计数,以及当前线程数,计算个任务增长比例的水线,动态增加或者回收线程池使用的线程个数。
3、基本框架实现代码
代码大体框架如下:
(1)实现两个对象 生产者(NJOB) 和 消费者(NWORKER)
(2)线程池 由 消费者组成的线程队列,以及生产者组成的任务等待队列。
(3)线程池主要由三个函数
thread_pool_create 创建线程池,并创建每个线程的回调函数
thread_pool_destory 销毁线程池
thread_pool_pushjob 将任务不断放入线程池的任务等待队列中
(4)线程池中每个线程的工作过程 thread_callback
从等待队列中取任务 。 gettask
执行该任务。 exectask
(5)任务由主线程抛入,提供对应的执行函数以及入参 。
//头插法
#define LL_ADD(item, list) do{ \
item->prev = NULL; \
item->next = list; \
if (list != NULL) list->prev = next; \
list = item; \
}while (0)
#define LL_REMOVE(item, list) do{ \
if(item->prev != NULL) item->prev->next = item->next; \
if(item->next != NULL) item->next->prev = item->prev; \
if (item == list) list = item->next; \
item->prev = NULL; \
item->next = NULL; \
}while (0)
struct NWORKER
{
pthread_t id;
int terminate;
nthreadpool* pool;
struct NWORKER* prev;
struct NWORKER* next;
}nworker;
struct NJOB
{
void (*job_func)(void* arg);
void* usr_data;
struct NJOB* prev;
struct NJOB* next;
}njob;
struct NTHREADPOOL
{
struct NWORKER* workers;
struct NJOB* wait_jobs;
pthread_cond_t cond; //条件变量
pthread_mutex_t mtx;
}nthreadpool;
void* thread_callback(void* arg)
{
nworker* worker = (nworker*)arg;
while (1)
{
//get job
phtread_mutex_lock(&worker->pool->mtx);
while (worker->pool->wait_jobs != NULL)
{
if (worker->terminate == 1)
{
break;
}
phtread_cond_wait(&worker->pool->cond, &worker->pool->mtx);
}
if (worker->terminate == 1)
{
phtread_mutex_unlock(&worker->pool->mtx);
break;
}
njob *job = worker->pool->wait_jobs;
if (job)
{
LL_REMOVE(job, worker->pool->wait_jobs);
}
phtread_mutex_unlock(&worker->pool->mtx);
if (job == NULL)
{
continue;
}
//exc
job->job_func(job->usr_data);
}
free(worker);
}
int thread_pool_create(nthreadpool* pool, int num_thread)
{
if (pool == NULL) return -1;
if (num_thread < 1) num_thread = 1;
memset(pool, 0, sizeof(nthreadpool));
pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
memcpy(&pool->cond, &blank_cond, sizeof(pthread_cond_t));
pthread_mutex_t blank_mtx = PTHREAD_MUTEX_INITIALIZER;
memcpy(&pool->mtx, &blank_mtx, sizeof(pthread_mutex_t));
int idx = 0;
for (idx = 0; idx < num_thread; ++idx)
{
nworker* worker = (nworker*)malloc(sizeof(nworker));
if (worker == NULL)
{
perror("malloc");
return idx;
}
memset(worker, 0, sizeof(nworker));
worker->pool = pool;
int ret = pthread_create(&worker->id, NULL, thread_callback, worker);
if (ret)
{
perror("pthread_create");
free(worker);
return idx;
}
LL_ADD(worker, pool->workers);
}
return idx;
}
int thread_pool_destory(nthreadpool* pool)
{
nworker* worker = NULL;
for (worker = pool->workers; worker != NULL; worker = worker->next)
{
worker->terminate = 1;
}
pthread_mutex_lock(&pool->mtx);
pthread_cond_broadcast(&pool->cond);
pthread_mutex_unlock(&pool->mtx);
}
int thread_pool_pushjob(nthreadpool* pool, njob* job)
{
pthread_mutex_lock(pool->mtx);
LL_ADD(job, pool->wait_jobs);
pthread_cond_signal(&pool->cond);
pthread_mutex_unlock(pool->mtx);
}
int main()
{
auto counter = [](njob* job)->void
{
if (job == NULL)
{
return;
}
int idx = *(int*)job->usr_data;
printf("idx : %d selfid:%u \n", idx, pthread_self());
free(job->usr_data);
free(job);
}
nthreadpool pool = { 0 };
int num_thread = 50;
thread_pool_create(pool, num_thread);
for (int i = 0; i < num_thread; ++i)
{
njob* job = (njob*)malloc(sizeof(njob));
job->job_func = counter;
job->usr_data = malloc(sizeof(int));
*(int*)job->usr_data = i;
thread_pool_pushjob(&pool, job);
}
return 0;
}