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");
}
确实是够简易的,不过好在只是简单的打印还是足够胜任了。
过于简易,所以问题很多,创建的线程都还没结束呢,主线程就完了。
还要分配任务的时候,修改了线程2的数据。但是可能释放的信号量给了线程3呢。