线程池增强一点点版本

简易线程池 增强内存的使用; 不再每一次malloc / free ; 把需要的内存先分配在deque中;

代码中有些许地方的更改 , 添加了deque后, 不再malloc(thread_pool) 了 也不再memset(thread_pool);

否则deque会出错;

 

下面2个版本, c++版本更容易实现些, 有现成的容器和function模版

版本1 , C版本:

// tpool.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <process.h>
#include <Windows.h>
#include <deque>
#define SPINCOUNT 4000

//一个任务, 用于存要执行的函数
typedef struct _task
{
	//可随意定义一个在线程中执行的函数,这种函数比较万用,就暂时先这么定义;
	void *(*pFunc)(void *arg);
	//函数参数
	void * arg;
	//下一个任务
	struct _task * next;
}thread_task;

typedef struct _thread_pool
{
	//unix 下 pthread_mutex_t mutex; win32 下用关键段代替 mutex
	CRITICAL_SECTION cs; 

	//unix 下 pthread_cond_t cond;
	CONDITION_VARIABLE cond;

	//一个任务链表 , 指向链表头 , 也可用 dequeue 替换
	thread_task * queue;  

	//可使用数 ,可用数与链表相关, 线程将判断此变量来查看链表中是否有额外的任务
	// 直到 aviliable_count == 0  && bEnd == 0 才将此线程投入睡眠
	int aviliable_count;
	
	// 是否结束 , 1 == 结束, 0 == 还在运行
	short bEnd;

	// 线程handler , waitforsingleobject 需要使用
	HANDLE * thread_handlers;

	//线程池大小
	int pool_size;

	// 任务存放的容器
	std::deque<thread_task*> taskBuffer;

	//扩张大小
	int taskBufferExtend;
	//容器 关键段
	CRITICAL_SECTION taskBufferCs;
}thread_pool;

unsigned int  WINAPI thread_routine(void *);

//初始化pool , pool_size: 线程池大小 , buffsize 容器大小
thread_pool * pool_create(int pool_size, int buffsize = 10)
{
	if (pool_size < 1)
		pool_size = 1;
	thread_pool * pool = new thread_pool;
	if (!pool)
		return NULL;

	//unix : pthread_mutex_init
	if (InitializeCriticalSectionAndSpinCount(&pool->cs, SPINCOUNT) == 0){
		printf("InitializeCriticalSectionAndSpinCount failed! err :%ld\n", GetLastError());
		InitializeCriticalSection(&pool->cs);
	}

	//unix : pthread_cond_init
	InitializeConditionVariable(&pool->cond);

	if (InitializeCriticalSectionAndSpinCount(&pool->taskBufferCs, SPINCOUNT) == 0){
		printf("InitializeCriticalSectionAndSpinCount failed! err :%ld\n", GetLastError());
		InitializeCriticalSection(&pool->taskBufferCs);
	}

	// 表头
	pool->queue = NULL;
	//是否结束
	pool->bEnd = FALSE;

	//线程个数 
	pool->pool_size = pool_size;

	//开始可用数 = 0
	pool->aviliable_count = 0;

	//存放handler 的地方 , unix 下可存放线程id (pthread_t), 用于后期回收(pthread_join) 
	pool->thread_handlers = (HANDLE*)malloc(pool_size * sizeof(HANDLE));

	//创建pool_size个线程 , unix 下 把_beginthreadex 替换成  pthread_create
	for (int i = 0; i < pool_size; ++i)
		pool->thread_handlers[i] =(HANDLE) _beginthreadex(0, 0, thread_routine, (void*)pool, 0, 0);

	int taskBuffSize = buffsize * pool_size;
	pool->taskBufferExtend = buffsize;

	for (int i = 0; i < taskBuffSize; ++i){
		pool->taskBuffer.push_back((thread_task *)malloc(sizeof(thread_task)));
	}

	return pool;
}

//线程函数, 一开始都在等待, 直到此线程被通知 WakeConditionVariable 
//unix 下 : pthread_cond_signal / pthread_cond_broadcast 
unsigned int WINAPI thread_routine(void * args)
{
	printf("thread id:%ld start!\n", GetCurrentThreadId());
	thread_pool * pool = (thread_pool *)args;
	while (true)
	{
		EnterCriticalSection(&pool->cs);
		/*
			阻塞,直到可用数 > 0
			unix 下使用pthread_cond_wait
			不论是 SleepConditionVariableCS 还是 pthread_cond_wait 都是
			执行时先加锁 , 被系统唤醒后解锁对应的 cs / mutex;
			要是没有通知, 则所有线程都投入睡眠
		*/
		while (!pool->bEnd && 0 == pool->aviliable_count)
			//投入睡眠 并 LeaveCriticalSection , 如果被唤醒则EnterCriticalSection
			SleepConditionVariableCS(&pool->cond, &pool->cs, INFINITE);

		/*
			所有线程退出的地方
			需要注意的是, 当SleepConditionVariableCS返回时会加锁 cs / mutex;
			否则是不会返回的,所以所以, 下面的代码中如果要退出线程,则先解锁
		*/

		if (pool->bEnd)
		{
			printf("thread id : %ld exit\n", GetCurrentThreadId());
			LeaveCriticalSection(&pool->cs); // pthread_mutex_unlock
			return 0;
		}

		//下面则是此线程将执行的任务;
		//可用数减1
		pool->aviliable_count--;
		//获取链表中第一个任务 
		thread_task *pTask = pool->queue;
		//指向原来的第2个任务
		pool->queue = pTask->next;
		//解锁
		LeaveCriticalSection(&pool->cs);

		//执行任务
		pTask->pFunc(pTask->arg);
		//清空task
		memset(pTask, 0, sizeof(thread_task));

		//把没用的task还回buffer中
		EnterCriticalSection(&pool->taskBufferCs);
		pool->taskBuffer.push_back(pTask);
		LeaveCriticalSection(&pool->taskBufferCs);
	}
}
int pool_submit(thread_pool * pool, void *(*pFunc)(void*arg), void *arg)
{
	//创建一个任务
	/*
		thread_task * pTask = (thread_task*)malloc(sizeof(thread_task));
		if (!pTask)
			return -1;
	*/
	thread_task *pTask = NULL;
	EnterCriticalSection(&pool->taskBufferCs);
	
	if (!pool->taskBuffer.empty())
	{
		pTask = pool->taskBuffer.front();
		pool->taskBuffer.pop_front();
		
	}
	else
	{
		pTask = (thread_task*)malloc(sizeof(thread_task));
		int len = pool->taskBufferExtend - 1;
		for (int i = 0; i < len; ++i)
			pool->taskBuffer.push_back((thread_task*)malloc(sizeof(thread_task)));

	}
	LeaveCriticalSection(&pool->taskBufferCs);
	//初始化
	pTask->arg = arg;
	pTask->pFunc = pFunc;
	pTask->next = NULL;

	//添加任务到 queue
	EnterCriticalSection(&pool->cs);
	thread_task * queue = pool->queue;
	//后来的任务添加到最后
	if (queue)
	{
		while (queue->next)
			queue = queue->next;
		queue->next = pTask;
	}
	else
		pool->queue = pTask;
	//可用数加1
	pool->aviliable_count++;
	//别忘记了
	LeaveCriticalSection(&pool->cs);

	//只唤醒等待的线程, 如果没有等待的线程,比如都在执行中,则无任何作用
	WakeConditionVariable(&pool->cond);
	return 0;
}


int pool_delete(thread_pool ** ptr_pool)
{
	thread_pool * pool = *ptr_pool;
	if (!pool)
		return -1;

	EnterCriticalSection(&pool->cs);
	//防止2次调用
	if (pool->bEnd){
		LeaveCriticalSection(&pool->cs);
		return -1;
	}
	pool->bEnd = 1; // 结束标记
	LeaveCriticalSection(&pool->cs);

	//唤醒所有线程 , pthread_cond_broadcast 
	WakeAllConditionVariable(&pool->cond);

	//回收线程资源  ,unix : pthread_join
	for (int i = 0; i < pool->pool_size; ++i)
		WaitForSingleObject(pool->thread_handlers[i], INFINITE);

	//释放queue
	thread_task **pHeader= &pool->queue;
	thread_task * entry = NULL;
	while (*pHeader){
		entry = *pHeader;
		*pHeader = entry->next;
		free(entry);
	}

	//释放taskbuffer
	while (!pool->taskBuffer.empty()){
		free(pool->taskBuffer.front());
		pool->taskBuffer.pop_front();
	}

	//unix 下需要 pthread_mutex_destroy , pthread_cond_destroy 
	DeleteCriticalSection(&pool->cs);
	DeleteCriticalSection(&pool->taskBufferCs);
	delete pool;
	pool = NULL;
	*ptr_pool = NULL;
	return 0;
}

//测试函数
void * func_in_thread(void * args)
{
	int d = 0;
	if (args)
		d = *(int*)args;
	printf("%s  in thread : %ld , arg:%d\n", __FUNCTIONW__, GetCurrentThreadId(), d);
	//假装执行代码
	Sleep(2000);
	return 0;
}



int _tmain(int argc, _TCHAR* argv[])
{
	
	thread_pool * pool = pool_create(2);
	int arr[20] = {};
	for (int i = 0; i < 20; ++i){
		arr[i] = i;
		pool_submit(pool, func_in_thread, arr+i);
	}

	getchar();
	pool_delete(&pool);
	
	
	return 0;
}


 

 

版本2, c++:

class TaskServer
{
private:
	std::list<std::function<void()>> taskList;
	CRITICAL_SECTION mutex;
	CONDITION_VARIABLE cond;
	HANDLE * _threadHandlers;
	BOOL bEnd;
	DWORD threadnum;
	
public:
	TaskServer(DWORD thread_num) :_threadHandlers(NULL), bEnd(FALSE), threadnum(thread_num)
	{
		InitializeCriticalSectionAndSpinCount(&mutex, SPINCOUNT);
		InitializeConditionVariable(&cond);
	}
	~TaskServer()
	{
		WaitForMultipleObjects(threadnum, _threadHandlers, TRUE, INFINITE);
		for (int i = 0; i < threadnum; ++i)
			CloseHandle(_threadHandlers[i]);
		delete[] _threadHandlers;
		DeleteCriticalSection(&mutex);
	}
	void addTask(const std::function<void()>& f)
	{
		EnterCriticalSection(&mutex);
		taskList.push_back(f);
		LeaveCriticalSection(&mutex);
		WakeConditionVariable(&cond);
	}
	void start()
	{
		if (threadnum < 1)
			threadnum = 1;
		_threadHandlers = new HANDLE[threadnum];
		for (int i = 0; i < threadnum; ++i)
			_threadHandlers[i] = (HANDLE)_beginthreadex(0, 0, TaskServer::thread_func, this, 0, 0);
	}
	void stop()
	{
		EnterCriticalSection(&mutex);
		if (bEnd){
			LeaveCriticalSection(&mutex);
			return;
		}
		bEnd = TRUE;
		LeaveCriticalSection(&mutex);
		WakeAllConditionVariable(&cond);
	}
	static unsigned int __stdcall thread_func(void * param)
	{
		TaskServer * pServer = (TaskServer *)param;
		pServer->onRun();
		return 0;
	}
	
	virtual void onRun()
	{
		while (true)
		{
			EnterCriticalSection(&mutex);

			while (!bEnd && taskList.empty())
				SleepConditionVariableCS(&cond, &mutex, INFINITE);
			
			if (bEnd){
				printf(" %ld end thread!\n" , GetCurrentThreadId());
				LeaveCriticalSection(&mutex);
				break;
			}
			
			std::function<void()> func = taskList.front();
			taskList.pop_front();
			LeaveCriticalSection(&mutex);
			func();
		}
		
	}
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值