一个行左右的简单线程池。用到了std::mutex和std::thread等新特性。
线程池模型
首先把每个函数抽象为一个任务(Task),任务的过程就是调用这个Task的run函数。然后把线程池中的线程封装为一个线程类(Thread),一直等待调度器分配任务(空闲状态),如果有任务分配立即进入忙状态。等任务执行结束再次变为空闲状态。最后是一个调度器类(TreadPool),包含任务队列(随时添加新任务),和一个包含了Thread的vector(线程池中的线程)。如果任务队列非空,调度器每次从中取出一个任务,然后轮询线程池,搜寻空闲线程并把这个任务交给线程。模型如下图所示:
代码实现
下面的代码实现了上述模型。其中Task类通过睡眠一定的秒数模拟任务,可以看到T1先执行完毕(1秒完毕),T2和T3在之后同时完毕,说明调度非常成功。
//linux,g++-std=c++14-ot*.cpp-pthread#includequeue#includeiostream#includemutex#includethread#includevector#includeunistd.hclassTask{private:intno;public:Task(intn){no=n;}//可以继承这个类重写该方法执行任务virtualvoidrun(){sleep(no);//构造时决定执行几秒,模拟线程运行std::coutnoT\n;}};classThread{private:std::thread_thread;bool_isfree;Task*_task;std::mutex_locker;public://构造Thread():_isfree(true),_task(nullptr){_thread=std::thread(Thread::run,this);_thread.detach();//放到后台,join是等待线程结束}//是否空闲boolisfree(){return_isfree;}//添加任务voidadd_task(Task*task){if(_isfree){_locker.lock();_task=task;_isfree=false;_locker.unlock();}}//如果有任务则执行任务,否则自旋voidrun(){while(true){if(_task){_locker.lock();_isfree=false;_task-run();_isfree=true;_task=nullptr;_locker.unlock();}}}};classThreadPool{private:std::queueTask*task_queue;std::vectorThread*_pool;std::mutex_locker;public://构造线程并后台执行,默认数量为10ThreadPool(intn=10){while(n--){Thread*t=newThread();_pool.push_back(t);}std::threadmain_thread(ThreadPool::run,this);main_thread.detach();}//释放线程池~ThreadPool(){for(inti=0;i_pool.size();++i){delete_pool[i];}}//添加任务voidadd_task(Task*task){_locker.lock();task_queue.push(task);_locker.unlock();}//轮询voidrun(){while(true){_locker.lock();if(task_queue.empty()){continue;}//寻找空闲线程执行任务for(inti=0;i_pool.size();++i){if(_pool[i]-isfree()){_pool[i]-add_task(task_queue.front());task_queue.pop();break;}}_locker.unlock();}}};intmain(){ThreadPooltp(2);Taskt1(1);Taskt2(3);Taskt3(2);tp.add_task(t1);tp.add_task(t2);tp.add_task(t3);sleep(4);//等待调度器结束,不然会崩溃return0;}