手写线程池

线程池

在这里插入图片描述
上图是一个线程池组件
线程池主要分三块东西,一个工作线程队列,一个任务队列还有一个管理组件(互斥锁和条件变量)
生活中很多场景和线程池比较类似
比如去银行取款,一个柜台就是一个工作线程,一个人是一个任务,看号码的窗口就是管理组件
再比如去食堂吃饭,一个打饭阿姨就是一个工作线程
下面实现了一个线程池组建

代码

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

#include <pthread.h>


//添加一个item到测试队列里面
#define LL_ADD(item, list) do { 	\
	item->prev = NULL;				\
	item->next = list;				\
	list = item;					\
} while(0)

//从测试队列里面删除一个item
#define LL_REMOVE(item, list) do {						\
	if (item->prev != NULL) item->prev->next = item->next;	\
	if (item->next != NULL) item->next->prev = item->prev;	\
	if (list == item) list = item->next;					\
	item->prev = item->next = NULL;							\
} while(0)

//工作线程
typedef struct NWORKER {
	pthread_t thread;//线程号
	int terminate;//是否结束
	struct NWORKQUEUE *workqueue;//工作队列指针
	struct NWORKER *prev;//上面一个工作线程指针
	struct NWORKER *next;//下一个工作线程指针
} nWorker;

//任务item,双向链表
typedef struct NJOB {
	void (*job_function)(struct NJOB *job);//回调函数
	void *user_data;//用户数据
	struct NJOB *prev;//前一个任务的指针
	struct NJOB *next;//后一个任务的指针
} nJob;

typedef struct NWORKQUEUE {
	struct NWORKER *workers; //头结点指针
	struct NJOB *waiting_jobs; //等待任务队列头指针
	pthread_mutex_t jobs_mtx; //互斥锁
	pthread_cond_t jobs_cond; //条件变量
} nWorkQueue;//工作队列

typedef nWorkQueue nThreadPool;

//工作线程执行函数
static void *ntyWorkerThread(void *ptr) {
	//拿出参数
	nWorker *worker = (nWorker*)ptr;

	while (1) {
		//上锁
		pthread_mutex_lock(&worker->workqueue->jobs_mtx);

		while (worker->workqueue->waiting_jobs == NULL) {
			if (worker->terminate) break;
			//条件等待
			pthread_cond_wait(&worker->workqueue->jobs_cond, &worker->workqueue->jobs_mtx);
		}
		
		//如果该线程要结束,则解锁退出
		if (worker->terminate) {
			pthread_mutex_unlock(&worker->workqueue->jobs_mtx);
			break;
		}
		
		//取第一个任务
		nJob *job = worker->workqueue->waiting_jobs;
		//移除任务队列中的任务
		if (job != NULL) {
			LL_REMOVE(job, worker->workqueue->waiting_jobs);
		}
		
		//解锁
		pthread_mutex_unlock(&worker->workqueue->jobs_mtx);

		if (job == NULL) continue;
		//执行回调函数
		job->job_function(job);
	}
	//退出,释放内存
	free(worker);
	pthread_exit(NULL);
}


//创建线程池
int ntyThreadPoolCreate(nThreadPool *workqueue, int numWorkers) {
	
	//检测参数
	if (numWorkers < 1) numWorkers = 1;
	memset(workqueue, 0, sizeof(nThreadPool));
	
	//初始化条件变量并拷贝过去
	pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
	memcpy(&workqueue->jobs_cond, &blank_cond, sizeof(workqueue->jobs_cond));
	
	//初始化互斥锁并拷贝过去
	pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;
	memcpy(&workqueue->jobs_mtx, &blank_mutex, sizeof(workqueue->jobs_mtx));

	//构建工作线程
	int i = 0;
	for (i = 0;i < numWorkers;i ++) {
		//分配内存
		nWorker *worker = (nWorker*)malloc(sizeof(nWorker));
		if (worker == NULL) {
			perror("malloc");
			return 1;
		}
		
		memset(worker, 0, sizeof(nWorker));
		//绑定工作线程与线程池
		worker->workqueue = workqueue;

		//创建线程 绑定函数
		int ret = pthread_create(&worker->thread, NULL, ntyWorkerThread, (void *)worker);
		if (ret) {
			
			perror("pthread_create");
			free(worker);

			return 1;
		}
		
		//将工作线程加入到工作线程队列中
		LL_ADD(worker, worker->workqueue->workers);
	}

	return 0;
}

//关闭线程池
void ntyThreadPoolShutdown(nThreadPool *workqueue) {
	nWorker *worker = NULL;
	//把terminate设置为true
	for (worker = workqueue->workers;worker != NULL;worker = worker->next) {
		worker->terminate = 1;
	}
	
	//上锁
	pthread_mutex_lock(&workqueue->jobs_mtx);

	workqueue->workers = NULL;
	workqueue->waiting_jobs = NULL;
	
	pthread_cond_broadcast(&workqueue->jobs_cond);
	//解锁
	pthread_mutex_unlock(&workqueue->jobs_mtx);
	
}

//把任务加入到任务队列中
void ntyThreadPoolQueue(nThreadPool *workqueue, nJob *job) {

	pthread_mutex_lock(&workqueue->jobs_mtx);

	LL_ADD(job, workqueue->waiting_jobs);
	//有任务了 发送信号
	pthread_cond_signal(&workqueue->jobs_cond);
	pthread_mutex_unlock(&workqueue->jobs_mtx);
	
}




#if 1

#define KING_MAX_THREAD			80
#define KING_COUNTER_SIZE		1000

//任务的回调函数
void king_counter(nJob *job) {

	int index = *(int*)job->user_data;

	printf("index : %d, selfid : %lu\n", index, pthread_self());
	
	free(job->user_data);
	free(job);
}



int main(int argc, char *argv[]) {
	//初始化线程池
	nThreadPool pool;
	//初始化各个组件
	ntyThreadPoolCreate(&pool, KING_MAX_THREAD);
	
	int i = 0;
	for (i = 0;i < KING_COUNTER_SIZE;i ++) {
		nJob *job = (nJob*)malloc(sizeof(nJob));
		if (job == NULL) {
			perror("malloc");
			exit(1);
		}
		//设置回调函数
		job->job_function = king_counter;
		job->user_data = malloc(sizeof(int));
		*(int*)job->user_data = i;
		//把任务加入到任务队列中
		ntyThreadPoolQueue(&pool, job);
		
	}

	getchar();
	printf("\n");

	
}

#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值