是其实也就是任务分发器,池子里预先跑着N个线程,可以往池子里提交任务。相对线程不断创建和销毁,特别对于大量的短时任务,线程池显然是很节省资源的。直接上代码:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
typedef void* (*job)(void*);
#define THREAD_PROC(i) (thread##i)
struct pthread_pool_t
{
pthread_mutex_t lock;
pthread_rwlock_t flag_lock;
pthread_t id;
job working_job;
int flag;
void* job_args;
struct pthread_pool_t* next;
};
void init_pool(struct pthread_pool_t* pool)
{
pool->id = 0;
pool->working_job = 0;
pool->flag = 0;
pool->next = NULL;
pool->job_args = 0;
pthread_mutex_init(&pool->lock,NULL);
pthread_rwlock_init(&pool->flag_lock,NULL);
}
void print_pool(struct pthread_pool_t* pool)
{
#if 0
printf("pool->lock = 0x%x\n",pool->lock);
printf("pool->id = 0x%x\n",pool->id);
printf("pool->working_job = 0x%x\n",pool->working_job);
printf("pool->flag = 0x%x\n",pool->flag);
printf("pool->args = 0x%x\n",pool->job_args);
printf("pool->next = 0x%x\n",pool->next);
#endif
}
void* thread1(void* p)
{
struct pthread_pool_t* ptr = (struct pthread_pool_t*)(p);
while(1){
//set a rwlock write-mode here , post_job will block there,
//only when ptr->flag is changed
pthread_rwlock_wrlock(&ptr->flag_lock);
/*printf("thread1 ... lock here\n");*/
pthread_mutex_lock(&(ptr->lock));
printf("thread1 got job = 0x%x\n",(unsigned int)ptr->working_job);
if(ptr->flag == 1){
ptr->flag = 0;
pthread_rwlock_unlock(&ptr->flag_lock);
(*ptr->working_job)(ptr->job_args);
}
//ptr->flag = 0;
//printf("thread1 done\n");
ptr->flag = 1;
//pthread_mutex_lock(&(ptr->lock));
}
return (void*)0;
}
void* thread2(void* p)
{
struct pthread_pool_t* ptr = (struct pthread_pool_t*)(p);
while(1) {
pthread_rwlock_wrlock(&ptr->flag_lock);
/*printf("thread2 ... lock here\n");*/
pthread_mutex_lock(&(ptr->lock));
printf("thread2 got job = 0x%x\n",(unsigned int)ptr->working_job);
if(ptr->flag == 1){
ptr->flag = 0;
pthread_rwlock_unlock(&ptr->flag_lock);
(*ptr->working_job)(ptr->job_args);
}
//ptr->flag = 0;
//printf("thread2 done\n");
ptr->flag = 1;
//pthread_mutex_lock(&(ptr->lock));
}
return (void*)0;
}
void* thread3(void* p)
{
struct pthread_pool_t* ptr = (struct pthread_pool_t*)(p);
while(1) {
pthread_rwlock_wrlock(&ptr->flag_lock);
/*printf("thread3 ... lock here\n");*/
pthread_mutex_lock(&(ptr->lock));
printf("thread3 got job = 0x%x\n",(unsigned int)ptr->working_job);
if(ptr->flag == 1){
ptr->flag = 0;
pthread_rwlock_unlock(&ptr->flag_lock);
(*ptr->working_job)(ptr->job_args);
}
//printf("thread3 done\n");
ptr->flag = 1;
//pthread_mutex_lock(&(ptr->lock));
}
return (void*)0;
}
int init_pthread_pool(struct pthread_pool_t** pool)
{
int i = 0;
job prepared_job[3] = {0};
struct pthread_pool_t* ptr = NULL;
struct pthread_pool_t* old = NULL;
prepared_job[0] = thread1;
prepared_job[1] = thread2;
prepared_job[2] = thread3;
for(;i < 3 ; i++) {
//printf("malloc\n");
ptr = (struct pthread_pool_t* )malloc(sizeof(struct pthread_pool_t));
init_pool(ptr);
/*//print_pool(ptr);*/
if(old != NULL) {
old->next = ptr;
//printf("old->next = ptr\n");
}
if(ptr == NULL) {
printf("init_pthread_pool malloc error\n");
return -1;
}
//Header fixed
if(*pool == NULL) {
//printf("*pool\n");
*pool = ptr;
}
//Init flag
ptr->flag = 1;
//ptr->lock = PTHREAD_MUTEX_INITIALIZER;
//Lock first
pthread_mutex_lock(&(ptr->lock));
pthread_create(&(ptr->id),NULL,prepared_job[i],ptr);
//Next
old = ptr;
//printf("old = ptr\n");
}
/*printf("pool = 0x%x\n",(int)pool);*/
//printf("In init\n");
////print_pool(*pool);
//Wait all thread ready
sleep(1);
return 0;
}
void release_pthread_pool(struct pthread_pool_t* header)
{
if(header == NULL)
return;
struct pthread_pool_t* ptr_pool = header;
struct pthread_pool_t* ptr_free = ptr_pool;
while(ptr_pool->next != NULL){
ptr_pool = ptr_pool->next;
pthread_mutex_destroy(&(ptr_free->lock));
pthread_rwlock_destroy(&(ptr_free->flag_lock));
pthread_cancel(ptr_pool->id);
free(ptr_free);
ptr_free = ptr_pool;
}
free(ptr_pool);
}
/**
* @brief post_job
* @param job
* @param args
* @param pool
* @return
*/
int post_job(job job,void* args, struct pthread_pool_t* pool)
{
int ret;
struct pthread_pool_t* ptr = pool;
//printf("head = 0x%x\n",(int)ptr);
//get non-busy thread id
while(ptr != NULL) {
//printf("post_job Start flag = %d\n",ptr->flag);
//Avoid dead lock
ret = pthread_rwlock_tryrdlock(&ptr->flag_lock);
if(ret != 0) {
//printf("Sleep for a while\n");
//usleep(10000);
} else {
printf("Should not lock\n");
pthread_rwlock_unlock(&(ptr->flag_lock));
}
//print_pool(ptr);
//try to get flag lock here if not block
if(ptr->flag == 1) {
//printf("post_job Register job=0x%x\n",job);
ptr->working_job = job;
ptr->job_args = args;
//deliver job to thread`
pthread_mutex_unlock(&(ptr->lock));
//ptr->flag = 0;
return 0;
} else {
//printf("post_job Next\n");
ptr = ptr->next;
}
}
printf("Ptr == NULL\n");
//Ptr == NULL or pool busy , still not find a working_job.
return -1;
}
int remove_job(job job,struct pthread_pool_t* pool)
{
return 0;
}
void* a_job(void* args)
{
printf("Job a running\n");
sleep(1);
printf("Job a done\n");
return (void*)0;
}
void* b_job(void* args)
{
printf("Job b running\n");
sleep(1);
printf("Job b done\n");
return (void*)0;
}
void* c_job(void* args)
{
printf("Job c running\n");
printf("Job c done\n");
return (void*)0;
}
int main(int argc, char* argv[])
{
printf("Go\n");
int ret;
struct pthread_pool_t* ThreadPool = NULL;
init_pthread_pool(&ThreadPool);
#if 1
//printf("ThreadPool\n");
//print_pool(ThreadPool);
#endif
/*printf("ThreadPool = 0x%x\n",(struct pthread_pool_t*)(&ThreadPool));*/
#if 0
ret = post_job(a_job,NULL, ThreadPool);
if(ret)
printf("post_job 1 failed\n");
ret = post_job(b_job,NULL, ThreadPool);
if(ret)
printf("post_job 2 failed\n");
ret =post_job(c_job,NULL, ThreadPool);
if(ret)
printf("post_job 3 failed\n");
#endif
int count = 0;
do{
if(count % 2)
ret =post_job(c_job,NULL, ThreadPool);
else
ret =post_job(a_job,NULL, ThreadPool);
if(ret)
printf("post_job may failed\n");
printf("Count = %d\n",count);
usleep(200000);
}while(count++ < 100);
release_pthread_pool(ThreadPool);
getchar();
return 0;
}
运行结果
取count=5
Go
Count = 0
thread1 got job = 0x40101f
Job a running
Should not lock
Count = 1
thread2 got job = 0x401081
Job c running
Job c done
Should not lock
Count = 2
thread2 got job = 0x40101f
Job a running
Should not lock
Should not lock
Count = 3
thread3 got job = 0x401081
Job c running
Job c done
Should not lock
Should not lock
Count = 4
thread3 got job = 0x40101f
Job a running
Job a done
Count = 5
thread1 got job = 0x401081
Job c running
Job c done
Count = 0
thread1 got job = 0x40101f
Job a running
Should not lock
Count = 1
thread2 got job = 0x401081
Job c running
Job c done
Should not lock
Count = 2
thread2 got job = 0x40101f
Job a running
Should not lock
Should not lock
Count = 3
thread3 got job = 0x401081
Job c running
Job c done
Should not lock
Should not lock
Count = 4
thread3 got job = 0x40101f
Job a running
Job a done
Count = 5
thread1 got job = 0x401081
Job c running
Job c done
说明
post_job是异步的。在资源不足时,提交会失败。
提交的任务越密集,池子初始化的线程越少,提交越容易失败。
实现的关键也是post_job.使用了两把锁:
一把锁是post_job唤醒thread,之后调用job的cb;
另一把锁,用来同步flag。使用trylock防止第1死锁。