简易线程池实现

是其实也就是任务分发器,池子里预先跑着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

说明

post_job是异步的。在资源不足时,提交会失败。
提交的任务越密集,池子初始化的线程越少,提交越容易失败。
实现的关键也是post_job.使用了两把锁:
一把锁是post_job唤醒thread,之后调用job的cb;
另一把锁,用来同步flag。使用trylock防止第1死锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值