自己写的线程池(可供他人调用)

/* thread_pool.h */
#ifndef THREAD_POOL
#define THREAD_POOL

#define MAX_THREAD 10
#define MIN_THREAD 1

typedef void (*threadJobFunc)(void *jobdata);
typedef struct _threadPool threadPool;
struct _threadPool {
	int quit;
	int have_work;				/* we add this arguement, to avoid workers's spurious wakeups. */
	int can_assign;				/* if a job is assigning, this will be zero. */
	pthread_t tids[MAX_THREAD];
	size_t max_workers;
	size_t min_workers;
	size_t free_workers;						/* worker who is free(sleep). */
	size_t nworkers;							/* now all workers' nunber. */
	pthread_mutex_t mutex;						/* control the data above. */
	
	threadJobFunc job_func;						/* function you want to call. */
	void * job_data;							/* it depends on you, maybe a struct or list and so on. */
	pthread_cond_t job_assign_cond;				/* ensure job assigning after former job have been receive colectly, as we don't use  job queue.*/
	
	pthread_cond_t worker_cond;					/* worker's sleep or wake up. */
	pthread_cond_t manger_cond;					/* manger's sleep or wakeup. */
};

static void * worker(void * arg);
void manger(threadPool * thread_pool);
int init_pool(threadPool * thread_pool);
void destory_pool(threadPool * thread_pool);

#endif
/* thread_pool.c */
#include <pthread.h>  
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "thread_pool.h"

/*
	Here worker is a thread, it do the job, when we have, if not it sleep.
*/
static void * worker(void * arg)
{

	threadJobFunc work_func;
	void * work_data;
	threadPool * thread_pool = (threadPool *)arg;
	while(1) {
		pthread_mutex_lock(&(thread_pool->mutex));
		while(!thread_pool->have_work && !thread_pool->quit) {
			pthread_cond_wait(&(thread_pool->worker_cond), &(thread_pool->mutex));
		}
		thread_pool->have_work = 0;					/* current work have been taken. */
		pthread_mutex_unlock(&(thread_pool->mutex));
		if (thread_pool->quit) break;				/* here stop the thread. */

		/* get the job data and function received and signal the job_assigned_cond. */
		work_func = thread_pool->job_func;
		work_data = thread_pool->job_data;
		pthread_mutex_lock(&(thread_pool->mutex));
		thread_pool->can_assign = 1;
		pthread_mutex_unlock(&(thread_pool->mutex));
		pthread_cond_signal(&(thread_pool->job_assign_cond));
		
		printf("job func called %p\n",thread_pool->job_data);
		work_func(work_data);	/* doing the job. */

		pthread_mutex_lock(&(thread_pool->mutex));
		thread_pool->free_workers++;
		pthread_mutex_unlock(&(thread_pool->mutex));
		
		pthread_cond_signal(&thread_pool->manger_cond);		/* send signal to the manger the worker is free. */
		printf("signal manger cond\n");
	}
	return;
}


/*
	Here is the mutiple threads' entrance.
*/
void manger(threadPool * thread_pool)
{
	int s;
	while(1) {
		if (thread_pool->free_workers > 0) {					/* Here read, we asume we don't need to lock. */

			/* This part's order can not be change. */
			pthread_mutex_lock(&(thread_pool->mutex));
			thread_pool->have_work = 1;
			thread_pool->free_workers--;
			pthread_mutex_unlock(&(thread_pool->mutex)); 
			pthread_cond_signal(&thread_pool->worker_cond);
			printf("signal worker_cond\n");
			break;
		}
		/* 
			Here we don't lock as there is only one manager, so we will not read the nworkers and create thread in 
			the same time. If there is more manger this must be locked, as threr maybe two  or more threads to read 
			nworkers(<max_workers), but after each threads creation, the nworkers may biger than max_workers. 
		*/
		if (thread_pool->nworkers < thread_pool->max_workers) {	
			s = pthread_create(&(thread_pool->tids[thread_pool->nworkers]), NULL, worker, thread_pool);
			if ( s!= 0) {
				printf("[%s:%d:%s]: %s\n", __FILE__, __LINE__, __FUNCTION__, 
					"Thread create error!\n");
				continue;
			} else {
				printf("create new worker\n");
			}
			
			pthread_mutex_lock(&(thread_pool->mutex));
			thread_pool->nworkers++;
			thread_pool->have_work = 1;
			pthread_mutex_unlock(&(thread_pool->mutex));
			
			pthread_cond_signal(&thread_pool->worker_cond);
			printf("signal worker_cond\n");
			break;
		}
		/* 
			Here exctly we don't have to lock the mutex, as olny one manger, and only manger will wait the manger_cond. 
			but  it seems we have to. Ok, it may  ensure there will no two threads wait the  thread_pool-> manger_cond in 
			the same time.
		*/
		pthread_mutex_lock(&(thread_pool->mutex));
		pthread_cond_wait(&(thread_pool->manger_cond), &(thread_pool->mutex));
		pthread_mutex_unlock(&(thread_pool->mutex));
	}
	return;
}


/*
	return 0 success. other fail.
*/
int init_pool(threadPool * thread_pool)
{
	int i, s;
	pthread_cond_init(&(thread_pool->worker_cond),NULL);
	pthread_cond_init(&(thread_pool->manger_cond),NULL);
	pthread_cond_init(&(thread_pool->job_assign_cond),NULL);
	pthread_mutex_init(&(thread_pool->mutex),NULL);

	thread_pool->quit = 0;
	thread_pool->can_assign = 1;
	thread_pool->have_work = 0;
	thread_pool->max_workers = MAX_THREAD;
	thread_pool->min_workers = MIN_THREAD;

	for (i=0; i<thread_pool->min_workers; i++) {
		s = pthread_create(&(thread_pool->tids[i]), NULL, worker, thread_pool);
		if (s != 0) {
			printf("[%s:%d:%s]: %s\n", __FILE__, __LINE__, __FUNCTION__, 
				"Thread create error!\n");
			return -1;
		} else {
			printf("create new worker\n");
		}
	}
	thread_pool->free_workers = thread_pool->min_workers;
	thread_pool->nworkers = thread_pool->min_workers;
	return 0;
}

void destory_pool(threadPool * thread_pool)
{
	int i = 0;
	thread_pool->quit = 1;	/* only the main thread wil change the arguement qiut, so we don't lock. */
	pthread_cond_broadcast(&(thread_pool->worker_cond));
	pthread_cond_broadcast(&(thread_pool->job_assign_cond));
	for (i=0; i<thread_pool->nworkers; i++)
		pthread_join(thread_pool->tids[i], NULL);
	pthread_cond_destroy(&(thread_pool->worker_cond));
	pthread_cond_destroy(&(thread_pool->manger_cond));
	pthread_cond_destroy(&(thread_pool->job_assign_cond));
	pthread_mutex_destroy(&(thread_pool->mutex));
}

/*
	if success return 0, else return -1.
	!!!attention: data must release by the job_func!
*/
int assign_job(threadPool * thread_pool, threadJobFunc job_func, void * data) {
	if (job_func == NULL) return -1;
	pthread_mutex_lock(&(thread_pool->mutex));
	while(!thread_pool->can_assign) {
		pthread_cond_wait(&(thread_pool->job_assign_cond), &(thread_pool->mutex));
	}
	thread_pool->can_assign = 0;
	pthread_mutex_unlock(&(thread_pool->mutex));
	printf("main call create cakes\n");
	thread_pool->job_func = job_func;
	thread_pool->job_data = data;
	manger(thread_pool);
	return 0;
}
/* test.c */
#include <stdio.h>
#include <pthread.h>  
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "thread_pool.h"

static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static int cakes = 0;
static threadPool thread_pool;

/* 
   release the mtx, when the thread is canceled, terminates by calling 
   pthread_exit(3) or a thread calls pthread_cleanup_pop().
*/ 
static void cleanup_handler(void *arg)  
{  
    printf("Cleanup handler of second thread./n");
    (void)pthread_mutex_unlock(&mtx);
}

static void func_create(void * arg)
{
	time_t ntime, end_time;
    pthread_cleanup_push(cleanup_handler, NULL);
	ntime = time(NULL);
	end_time = ntime + 5;
	while(ntime < end_time)			/* do create */
	{
		ntime = time(NULL);
	}
	pthread_mutex_lock(&mtx);
	cakes += *((int*)arg);
	pthread_mutex_unlock(&mtx);
	printf("create %d\n", *((int*)arg));
	free(arg);
    pthread_cleanup_pop(0);  
    return;  
}

static void func_eat(void * arg)  
{
	time_t ntime = time(NULL);
	time_t end_time = ntime + 5;
	/* do eat. */
	while (ntime < end_time) {
		ntime = time(NULL);
	}
	pthread_cleanup_push(cleanup_handler, NULL);
	/*
		? PROBLEM:
		here may cause eat success, but found cakes equal to 0.
		if decrease cakes first, may cause eat fail, but create more cakes than
		max cake number.
	*/
	pthread_mutex_lock(&mtx);                 
	cakes -= *((int*)arg);
	printf("eate %d\n", *((int*)arg)); 
	pthread_mutex_unlock(&mtx);
	free(arg);
    pthread_cleanup_pop(0);  
    return;  
}

int main(void)
{
	int * data;
	time_t ntime, end_time;
	char qf[10];
	int num = 0;
	int num_eat = 0;
	if ( init_pool(&thread_pool) ) goto clean;
	/* main thread are working. */
	ntime = time(NULL);
	end_time = ntime + 5;
	while(1)
	{
		ntime = time(NULL);
		if (ntime > end_time) {
			ntime = time(NULL);
			end_time = ntime + 50;
			printf("exit(y/n)?");
			scanf("%s", qf);
			if (qf[0] == 'y' || qf[0] == 'Y') {
				break;
			}
		}
		
		/*
			we must ensure job assigning after the former job have been receive colectly.
			we will release the lock, when the job receive by a thread.
		*/
		data = (int *)malloc(sizeof(int));
		*data = 2;
		num += *data;
		assign_job(&thread_pool, func_create, data);
		
		data = (int *)malloc(sizeof(int));
		*data = 2;
		num_eat += *data;
		assign_job(&thread_pool, func_eat, data);
		
	}
clean:
	destory_pool(&thread_pool);
	printf("create all: %d\teat all: %d\t left: %d\n", num, num_eat, cakes);
    return 0;  
} 



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值