線程池的實現(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

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