• 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呢。

    好在,简单的打印完成了。说明思路是没错的。只是效率之类的问题还没有考虑。看来线程池,关键就在于线程池如何与创建的线程进行通信和交换数据了。
  • 相关阅读:
    请简单介绍spring支持的常用数据库事务传播属性和事务隔离级别
    Spring Bean的作用域
    成员变量与局部变量的区别
    递归与迭代
    方法参数的传递机制 ---- 值传递
    windows phone 动画 当子控件超出父控件返回时
    把dataset 输出到 excel
    代码段
    c++ 学习纪录
    做自己的代码生成器
  • 原文地址:https://www.cnblogs.com/dayq/p/16126140.html
Copyright © 2020-2023  润新知