C++简易线程池

C++简易线程池

原理:

thread a = thread(theadProc,param);
线程构造以后,线程执行的函数就不能改变了,一旦函数运行结束,线程也就终止。
所以要实现线程不停的切换任务,就只能对param动手了。
让param变成一个装有函数指针以及该函数执行所需参数的数据结构。
让线程池和线程通过param参数来交换数据,分配任务。

1.函数指针。

代码:

#include<iostream>
#include<windows.h>
using namespace std;
int add(int a,int b)
{
	return a + b;
}
int main()
{
	using ADD = int(*)(int,int);//函数指针类型
	LPVOID a= (LPVOID)&add;
	ADD adda = (ADD)a;
	cout<<adda(1,3)<<endl;
}

2.线程间同步。

可见本人另一篇博客。
C++多线程同步总结

3.代码:

#include<iostream>
#include<thread>
#include<mutex>
#include<windows.h>
#include<queue>
using namespace std;
#define THREA_NUM	4
mutex mu;
mutex mu2;
HANDLE sem;
HANDLE semHave;

//线程池和线程就通过这个结构交换数据
struct WORK
{
	PVOID work;
	PVOID param;
};
//简单起见,就让每个线程做一样的任务
void* print(void* num)
{
	mu.lock();
	printf("this is print %d work,num = %d\n",this_thread::get_id(),(int)num);
	mu.unlock();
}
void* print2(void* num)
{
	mu.lock();
	printf("this is print2 %d work, = %d\n",this_thread::get_id(),(int)num);
	mu.unlock();
}
using PRINT = void*(*)(void*);
void threadToWork(WORK &work)
{
	while(1)
	{
		WaitForSingleObject(sem,INFINITE);//通过信号量,让线程接受任务
		PRINT print = (PRINT)(work.work);
		print(work.param);
		mu2.lock();
		work.work = 0;
		mu2.unlock();
		ReleaseSemaphore(semHave,1,NULL);//任务执行完毕,通知线程池
	}
}
struct threadPool
{
	queue<WORK> q;//任务队列,也没有设置容量
	thread xcArr[THREA_NUM];//线程句柄数组
	WORK haveWork[THREA_NUM];//每个线程的数据
	void start()
	{
		sem = CreateSemaphore(NULL,0,THREA_NUM,"semaphore");
		semHave = CreateSemaphore(NULL,THREA_NUM,THREA_NUM,"semaphorehave");
		for(int i=0;i<THREA_NUM;i++)
		{
			haveWork[i].work = 0;
			xcArr[i] = thread(threadToWork,ref(haveWork[i]));//ref是必须的,线程间引用
		}
	}
	bool addWork(WORK newWork)
	{
		q.push(newWork);
		while(!q.empty())
		{
			WORK tempWork = q.front();
			q.pop();
			WaitForSingleObject(semHave,INFINITE);//等一个闲着的线程
			for(int i=0;i<THREA_NUM;i++)
			{
				if(haveWork[i].work==0)
				{
					mu2.lock();
					haveWork[i] = tempWork;//修改该线程的数据
					mu2.unlock();
					ReleaseSemaphore(sem,1,NULL);//通知线程
					break;
				}
			}
		}
		return true;
	}
	bool noWork()
	{
		for(int i=0;i<4;i++)
		{
			if(haveWork[i].work!=0)
			{
				return false;
			}
		}
		return true;
	}
};
int main()
{
	threadPool pool;
	pool.start();
	WORK work;
	
	for(int i=0;i<10;i++)
	{
		if(i%2==0)//做不同的任务
		{
			work.work = (LPVOID)&print;
		}
		else
		{
			work.work = (LPVOID)&print2;
		}
		work.param = (PVOID)i;
		pool.addWork(work);
	}
	while(!pool.noWork())
	{
		Sleep(2000);
	}
	WaitForSingleObject(semHave,INFINITE);
	WaitForSingleObject(semHave,INFINITE);
	WaitForSingleObject(semHave,INFINITE);
	WaitForSingleObject(semHave,INFINITE);
	CloseHandle(sem);
	CloseHandle(semHave);
	system("pause");
}

image

确实是够简易的,不过好在只是简单的打印还是足够胜任了。

过于简易,所以问题很多,创建的线程都还没结束呢,主线程就完了。

还要分配任务的时候,修改了线程2的数据。但是可能释放的信号量给了线程3呢。

好在,简单的打印完成了。说明思路是没错的。只是效率之类的问题还没有考虑。看来线程池,关键就在于线程池如何与创建的线程进行通信和交换数据了。
posted @ 2022-04-10 15:42  念秋  阅读(188)  评论(0编辑  收藏  举报