线程池的实现(c语言)

/** threadpool.h */

#include <pthread.h>
struct job {
	void *(*callback_function)(void *arg);	//线程回调函数
	void *arg;				//回调函数参数
	struct job *next;
};

struct threadpool;

/* 
 * threadpool_init
 * @thread_num: 线程池开启的线程个数
 * @queue_max_num: 队列的最大job个数
 * return: 成功:线程池地址 失败:NULL
 */
struct threadpool *threadpool_init(int thread_num, int queue_max_num);

/* 
 * threadpool_add_job
 * @pool: 线程池地址
 * @callback_function: 回调函数参数
 * @arg: 回调函数参数
 * return: 成功:0 失败:-1struct threadpool
 */
int threadpool_add_job(struct threadpool *pool, void *(*callback_function)(void *arg), void *arg);

/* 
 * threadpool_destroy
 * @pool: 线程池地址
 * return: 成功:0 失败:-1
 */
int threadpool_destroy(struct threadpool *pool);


/** threadpool.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "threadpool.h"

struct threadpool
{
	int thread_num;			//线程池中开启线程的个数
	int queue_max_num;		//队列中最大job的个数
	struct job *head;		//指向job的头指针
	struct job *tail;		//指向job的尾指针
	pthread_t *pthreads;		//线程池中所有线程的pthread_t
	pthread_mutex_t mutex;		//互斥信号量
	pthread_cond_t queue_empty;	//队列为空的条件变量
	pthread_cond_t queue_not_empty; //队列不为空的条件变量
	pthread_cond_t queue_not_full;	//队列不为满的条件变量
	int queue_cur_num;		//队列当前的job个数
	int queue_close;		//队列是否已经关闭
	int pool_close;			//线程池是否已经关闭
};

/* 
 threadpool_function --(queue_not_full)--> threadpool_add_job
 threadpool_add_job --(queue_not_empty)--> threadpool_function
 threadpool_function --(queue_empty)--> threadpool_destroy
 */

void *threadpool_function(void *arg)
{
	struct threadpool *pool = (struct threadpool*)arg;
	struct job *pjob = NULL;
	while (1) {
		pthread_mutex_lock(&(pool->mutex));
		while ((pool->queue_cur_num == 0) && !pool->pool_close) {
			pthread_cond_wait(&(pool->queue_not_empty), &(pool->mutex));
		}
		if (pool->pool_close) {
			pthread_mutex_unlock(&(pool->mutex));
			pthread_exit(NULL);
		}
		pool->queue_cur_num--;
		pjob = pool->head;
		if (pool->queue_cur_num == 0) {
			pool->head = pool->tail = NULL;
		} else {
			pool->head = pjob->next;
		}
		if (pool->queue_cur_num == 0) {
			pthread_cond_signal(&(pool->queue_empty));
		}
		if (pool->queue_cur_num < pool->queue_max_num) {
			pthread_cond_broadcast(&(pool->queue_not_full));
		}
		pthread_mutex_unlock(&(pool->mutex));

		(*(pjob->callback_function))(pjob->arg);
		free(pjob);
		pjob = NULL;	
	}
}

int threadpool_add_job(struct threadpool *pool, void *(*callback_function)(void *arg), void *arg)
{
	assert(pool != NULL);
	assert(callback_function != NULL);
	assert(arg != NULL);

	pthread_mutex_lock(&(pool->mutex));
	while ((pool->queue_cur_num == pool->queue_max_num) && !(pool->queue_close || pool->pool_close)) {
		pthread_cond_wait(&(pool->queue_not_full), &(pool->mutex));
	}
	if (pool->queue_close || pool->pool_close) {
		pthread_mutex_unlock(&(pool->mutex));
		return -1;
	}
	struct job *pjob =(struct job*) malloc(sizeof(struct job));
	if (NULL == pjob) {
		pthread_mutex_unlock(&(pool->mutex));
		return -1;
	} 
	pjob->callback_function = callback_function;	
	pjob->arg = arg;
	pjob->next = NULL;
	if (pool->head == NULL) {
		pool->head = pool->tail = pjob;
		pthread_cond_broadcast(&(pool->queue_not_empty));
	} else {
		pool->tail->next = pjob;
		pool->tail = pjob;	  
	}
	pool->queue_cur_num++;
	pthread_mutex_unlock(&(pool->mutex));
	return 0;
}

struct threadpool *threadpool_init(int thread_num, int queue_max_num)
{
	struct threadpool *pool = NULL;
	do {
		pool = malloc(sizeof(struct threadpool));
		if (NULL == pool) {
			printf("failed to malloc threadpool!\n");
			break;
		}
		pool->thread_num = thread_num;
		pool->queue_max_num = queue_max_num;
		pool->queue_cur_num = 0;
		pool->head = NULL;
		pool->tail = NULL;
		if (pthread_mutex_init(&(pool->mutex), NULL)) {
			printf("failed to init mutex!\n");
			break;
		}
		if (pthread_cond_init(&(pool->queue_empty), NULL)) {
			printf("failed to init queue_empty!\n");
			break;
		}
		if (pthread_cond_init(&(pool->queue_not_empty), NULL)) {
			printf("failed to init queue_not_empty!\n");
			break;
		}
		if (pthread_cond_init(&(pool->queue_not_full), NULL)) {
			printf("failed to init queue_not_full!\n");
			break;
		}
		pool->pthreads = malloc(sizeof(pthread_t) * thread_num);
		if (NULL == pool->pthreads) {
			printf("failed to malloc pthreads!\n");
			break;
		}
		pool->queue_close = 0;
		pool->pool_close = 0;
		int i;
		for (i = 0; i < pool->thread_num; ++i) {
			pthread_create(&(pool->pthreads[i]), NULL,
					threadpool_function, (void *)pool);
		}
		
		return pool;	
	} while (0);
	
	return NULL;
}

int threadpool_destroy(struct threadpool *pool)
{
	assert(pool != NULL);
	pthread_mutex_lock(&(pool->mutex));
	if (pool->queue_close || pool->pool_close) {
		pthread_mutex_unlock(&(pool->mutex));
		return -1;
	}
	
	pool->queue_close = 1;
	while (pool->queue_cur_num != 0) {
		pthread_cond_wait(&(pool->queue_empty), &(pool->mutex));
	}	 
	
	pool->pool_close = 1;
	pthread_mutex_unlock(&(pool->mutex));
	pthread_cond_broadcast(&(pool->queue_not_empty));
	pthread_cond_broadcast(&(pool->queue_not_full));
	int i;
	for (i = 0; i < pool->thread_num; ++i) {
		pthread_join(pool->pthreads[i], NULL);
	}
	
	pthread_mutex_destroy(&(pool->mutex));
	pthread_cond_destroy(&(pool->queue_empty));
	pthread_cond_destroy(&(pool->queue_not_empty));   
	pthread_cond_destroy(&(pool->queue_not_full));	  

	free(pool->pthreads);
	free(pool);
	return 0;
}

/** poolmain.c */

#include <stdio.h>
#include <stdlib.h>
#include "threadpool.h"

#define JOBNUM	2000

void *work(void *arg)
{
	printf("threadpool callback fuction : %s.\n", (char *)arg);
	free(arg);
	usleep(1000 * 100);

	return NULL;
}

int main(void)
{
	struct threadpool *pool = threadpool_init(10, 20);
	int loop = JOBNUM;
	while (loop--) {
	char *buf = (char *)malloc(sizeof(char) * 32);
		snprintf(buf, 32, "%d", JOBNUM - loop);
		threadpool_add_job(pool, work, buf);
	}

	threadpool_destroy(pool);
	return 0;
}

       pthread_cond_signal restarts one of the threads that are waiting on the condition variable  cond.
       If  no  threads  are  waiting  on  cond, nothing happens. If several threads are waiting on cond,
       exactly one is restarted, but it is not specified which.

       pthread_cond_broadcast restarts all the threads that are waiting on the condition variable  cond.
       Nothing happens if no threads are waiting on cond.

       pthread_cond_wait  atomically  unlocks  the mutex (as per pthread_unlock_mutex) and waits for the
       condition variable cond to be signaled. The thread execution is suspended and  does  not  consume
       any  CPU  time  until the condition variable is signaled. The mutex must be locked by the calling
       thread  on  entrance  to   pthread_cond_wait.   Before   returning   to   the   calling   thread,
       pthread_cond_wait re-acquires mutex (as per pthread_lock_mutex).

       Unlocking  the  mutex  and  suspending on the condition variable is done atomically. Thus, if all
       threads always acquire the mutex before signaling the condition, this guarantees that the  condi‐
       tion cannot be signaled (and thus ignored) between the time a thread locks the mutex and the time
       it waits on the condition variable.

pthread_cond_wait 在进入休眠时会把互斥锁解锁,唤醒时会获取互斥锁

所以在没有add job之前,线程池里所有的线程都是cond wait的状态,等待queue_not_empty

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章