线程池代码分析

该文章展示了一个用C语言实现的线程池库,通过`pthread`实现线程的创建、销毁和管理。线程池可以创建指定数量的线程,按需分配任务,并在无任务时保持线程存活或自动减少线程数量。`pthread_cleanup_push`和`pthread_cleanup_pop`用于清理操作,确保资源释放。示例代码中包含线程池的创建、任务队列的管理以及等待所有任务完成和销毁线程池的函数。
摘要由CSDN通过智能技术生成

在github上看到这个代码,就down下来研究了一下

编译命令 gcc -g -o thread_pool_active thread_pool_active.c  -lpthread


/*
 * Author: WangBoJing
 * email: 1989wangbojing@gmail.com 
 * github: https://github.com/wangbojing
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <signal.h>
#include <errno.h>

#include <time.h>
#include <unistd.h>
#include <pthread.h>



typedef void (*JOB_CALLBACK)(void *);

typedef struct NJOB {
	struct NJOB *next;
	JOB_CALLBACK func;
	void *arg;
} nJob;

typedef struct NWORKER {
	struct NWORKER *active_next;
	pthread_t active_tid;
} nWorker;

typedef struct NTHREADPOOL {
	struct NTHREADPOOL *forw;
	struct NTHREADPOOL *back;

	pthread_mutex_t mtx;
	
	pthread_cond_t busycv;
	pthread_cond_t workcv;
	pthread_cond_t waitcv;

	nWorker *active;
	nJob *head;
	nJob *tail;

	pthread_attr_t attr;
	
	int flags;
	unsigned int linger;

	int minimum;
	int maximum;
	int nthreads;
	int idle;
	
} nThreadPool;

static void* ntyWorkerThread(void *arg);

#define NTY_POOL_WAIT			0x01
#define NTY_POOL_DESTROY		0x02


static pthread_mutex_t nty_pool_lock = PTHREAD_MUTEX_INITIALIZER;
static sigset_t fillset;
nThreadPool *thread_pool = NULL;



static int ntyWorkerCreate(nThreadPool *pool) {

	sigset_t oset;
	pthread_t thread_id;

	pthread_sigmask(SIG_SETMASK, &fillset, &oset);
	int error = pthread_create(&thread_id, &pool->attr, ntyWorkerThread, pool);
	pthread_sigmask(SIG_SETMASK, &oset, NULL);

	return error;
}

static void ntyWorkerCleanup(nThreadPool * pool) {

	--pool->nthreads;

	if (pool->flags & NTY_POOL_DESTROY) 
	{
		if (pool->nthreads == 0) 
		{
			pthread_cond_broadcast(&pool->busycv);
		}
	} else if (pool->head != NULL && pool->idle < 0 && pool->nthreads < pool->maximum && ntyWorkerCreate(pool) == 0) {
		pool->nthreads ++;
	}
	pthread_mutex_unlock(&pool->mtx);
	
}



//通知主线程,让主线程结束等待
static void ntyNotifyWaiters(nThreadPool *pool) {
	
	if (pool->head == NULL && pool->active == NULL) 
	{
		pool->flags &= ~NTY_POOL_WAIT;
		pthread_cond_broadcast(&pool->waitcv);
	}
}



//当子线程执行完任务后,把子线程从活跃队列里剔除出去
static void ntyJobCleanup(nThreadPool *pool) {
	
	pthread_t tid = pthread_self();
	nWorker *activep;
	nWorker **activepp;
	
	pthread_mutex_lock(&pool->mtx);



/*原有逻辑---begin
	for (activepp = &pool->active;(activep = *activepp) != NULL;activepp = &activep->active_next) {
		*activepp = activep->active_next;
		break;
	}

原有逻辑---end */

	for (activepp = &pool->active; (activep = *activepp) != NULL; activepp = &activep->active_next)
	{
		if (tid == activep->active_tid)
		{
			*activepp = activep->active_next;
			printf("break__tid: %lu\n", activep->active_tid);
			break;
		}
	}

	if (pool->flags & NTY_POOL_WAIT) ntyNotifyWaiters(pool);
	
}

//线程工作函数的逻辑
static void* ntyWorkerThread(void *arg) {

	nThreadPool *pool = (nThreadPool*)arg;
	nWorker active;
	
	int timeout;
	struct timespec ts;
	JOB_CALLBACK func;

	pthread_mutex_lock(&pool->mtx);
	pthread_cleanup_push(ntyWorkerCleanup, pool);

	active.active_tid = pthread_self();
	
	while (1) 
	{

		pthread_sigmask(SIG_SETMASK, &fillset, NULL);
		pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

		timeout = 0;
		pool->idle ++;

		if (pool->flags & NTY_POOL_WAIT) {
			ntyNotifyWaiters(pool);
		}

		while (pool->head == NULL && !(pool->flags & NTY_POOL_DESTROY)) 
		{

			if (pool->nthreads <= pool->minimum) 
			{
				
				pthread_cond_wait(&pool->workcv, &pool->mtx);
				
			} 
			else 
			{
			    //任务少,初始化创建的线程多时,没有分到任务的线程执行else逻辑
				clock_gettime(CLOCK_REALTIME, &ts);
				ts.tv_sec += pool->linger;

				if (pool->linger == 0 || pthread_cond_timedwait(&pool->workcv, &pool->mtx, &ts) == ETIMEDOUT) {
					timeout = 1;
					break;
				}
			}
		}

		pool->idle --;
		if (pool->flags & NTY_POOL_DESTROY) break;

		nJob *job = pool->head;		
		if (job != NULL) 
		{
			timeout = 0;
			func = job->func;
			
			void *job_arg = job->arg;

			//*管理任务队列 尾插
			pool->head = job->next;

			if (job == pool->tail) 
			{
				pool->tail = NULL;
			}
			
			//活跃线程队列 头插法
			active.active_next = pool->active;
			pool->active = &active;

			pthread_mutex_unlock(&pool->mtx);

			pthread_cleanup_push(ntyJobCleanup, pool);

			free(job);
			func(job_arg);
			
			//pthread_cleanup_pop(1)  执行 ntyJobCleanup
			pthread_cleanup_pop(1);
		}

		if (timeout && (pool->nthreads > pool->minimum)) {
			break;
		}

	}

    //pthread_cleanup_pop(1)执行ntyWorkerCleanup
	pthread_cleanup_pop(1);
	
	return NULL;
	
}


//设置线程属性
static void ntyCloneAttributes(pthread_attr_t *new_attr, pthread_attr_t *old_attr) {

	struct sched_param param;
	void *addr;
	size_t size;
	int value;

	pthread_attr_init(new_attr);
	
	if (old_attr != NULL) {
		pthread_attr_getstack(old_attr, &addr, &size);
		pthread_attr_setstack(new_attr, NULL, size);

		pthread_attr_getscope(old_attr, &value);
		pthread_attr_setscope(new_attr, value);

		pthread_attr_getinheritsched(old_attr, &value);
		pthread_attr_setinheritsched(new_attr, value);

		pthread_attr_getschedpolicy(old_attr, &value);
		pthread_attr_setschedpolicy(new_attr, value);

		pthread_attr_getschedparam(old_attr, &param);
		pthread_attr_setschedparam(new_attr, &param);

		pthread_attr_getguardsize(old_attr, &size);
		pthread_attr_setguardsize(new_attr, size);
	}

	pthread_attr_setdetachstate(new_attr, PTHREAD_CREATE_DETACHED);
	
}



nThreadPool *ntyThreadPoolCreate(int min_threads, int max_threads, int linger, pthread_attr_t *attr) {

	sigfillset(&fillset);
	if (min_threads > max_threads || max_threads < 1) {
		errno = EINVAL;
		return NULL;
	}

	nThreadPool *pool = (nThreadPool*)malloc(sizeof(nThreadPool));
	if (pool == NULL) {
		errno = ENOMEM;
		return NULL;
	}
	
	pthread_mutex_init(&pool->mtx, NULL);

	pthread_cond_init(&pool->busycv, NULL);
	pthread_cond_init(&pool->workcv, NULL);
	pthread_cond_init(&pool->waitcv, NULL);

	pool->active = NULL;
	pool->head = NULL;
	pool->tail = NULL;
	pool->flags = 0;
	pool->linger = linger;
	pool->minimum = min_threads;
	pool->maximum = max_threads;
	pool->nthreads = 0;
	pool->idle = 0;

	ntyCloneAttributes(&pool->attr, attr);

	pthread_mutex_lock(&nty_pool_lock);
	
	if (thread_pool == NULL) {

		pool->forw = pool;
		pool->back = pool;
		
		thread_pool = pool;
		
	} else {

		thread_pool->back->forw = pool;
		pool->forw = thread_pool;
		pool->back = thread_pool->back;
		thread_pool->back = pool;
		
	}

	pthread_mutex_unlock(&nty_pool_lock);

	return pool;
	
}


int ntyThreadPoolQueue(nThreadPool *pool, JOB_CALLBACK func, void *arg) {


	nJob *job = (nJob*)malloc(sizeof(nJob));
	if (job == NULL) {
		errno = ENOMEM;
		return -1;
	}

	job->next = NULL;
	job->func = func;
	job->arg = arg;

	pthread_mutex_lock(&pool->mtx);

	if (pool->head == NULL) {
		pool->head = job;
	} else {
		pool->tail->next = job;
	}
	pool->tail = job;

	if (pool->idle > 0) {
		pthread_cond_signal(&pool->workcv);
	} else if (pool->nthreads < pool->minimum && ntyWorkerCreate(pool) == 0) {
		pool->nthreads ++;
	}

	pthread_mutex_unlock(&pool->mtx);
	
	return 0;

}


void nThreadPoolWait(nThreadPool *pool) {

	printf("You are nThreadPoolWait !!!!\n");
	pthread_mutex_lock(&pool->mtx);

	pthread_cleanup_push(pthread_mutex_unlock, &pool->mtx);

	while (pool->head != NULL || pool->active != NULL) {
		pool->flags |= NTY_POOL_WAIT;
		pthread_cond_wait(&pool->waitcv, &pool->mtx);
	}
	
	pthread_cleanup_pop(1);
}


void nThreadPoolDestroy(nThreadPool *pool) {

	printf("You are nThreadPoolDestroy !!!!\n");
	nWorker *activep;
	nJob *job;

	pthread_mutex_lock(&pool->mtx);
	pthread_cleanup_push(pthread_mutex_unlock, &pool->mtx);

	pool->flags |= NTY_POOL_DESTROY;
	pthread_cond_broadcast(&pool->workcv);

	for (activep = pool->active;activep != NULL;activep = activep->active_next) {
		pthread_cancel(activep->active_tid);
	}

	while (pool->nthreads != 0) {
		pthread_cond_wait(&pool->busycv, &pool->mtx);
	}

	pthread_cleanup_pop(1);

	pthread_mutex_lock(&nty_pool_lock);

	if (thread_pool == pool) {
		thread_pool = pool->forw;
	} 

	if (thread_pool == pool) {
		thread_pool = NULL;
	} else {
		pool->back->forw = pool->forw;
		pool->forw->back = pool->back;
	}

	pthread_mutex_unlock(&nty_pool_lock);
	
	for (job = pool->head;job != NULL;job = pool->head) {
		pool->head = job->next;
		free(job);
	}

	pthread_attr_destroy(&pool->attr);
	free(pool);
}


/********************************* debug thread pool *********************************/



void king_counter(void *arg) {

	int index = *(int*)arg;

	printf("index : %d, selfid : %lu\n", index, pthread_self());
	
	free(arg);
	usleep(1);
}


#define KING_COUNTER_SIZE 10

int main(int argc, char *argv[]) {

	nThreadPool *pool = ntyThreadPoolCreate(3, 10, 15, NULL);

	int i = 0;
	for (i = 0;i < KING_COUNTER_SIZE;i ++) 
	{
		int *index = (int*)malloc(sizeof(int));
		
		memset(index, 0, sizeof(int));
		memcpy(index, &i, sizeof(int));
		
		ntyThreadPoolQueue(pool, king_counter, index);
		
	}

	nThreadPoolWait(pool);

	nThreadPoolDestroy(pool);

	getchar();
	printf("You are very good !!!!\n");
}




linux高级编程之线程间的通信(pthread_cleanup_push和pthread_cleanup_pop)_那时风起的博客-CSDN博客

pthread_setcancelstate()和pthread_setcanceltype()_MaxLiuZhenGuo的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值