介绍
线程池中,生产者线程(主线程 Master)的主要工作是给任务队列提交任务函数实现;
而消费者线程(Slave)主要工作是从任务队列取任务并执行任务函数。
给任务队列提交任务函数实现(Master)
// 给线程池提交任务
// 这是一个对队列的操作,有临界资源
void ThreadPool::submitTask(std::shared_ptr<Task> sp)
{
// 获取锁
std::unique_lock<std::mutex> lck(taskQueMtx_);
// 线程的通信, 等待队列有空余
//while (taskQue_.size() == taskQueMaxThreadhold_)
//{
// notFull_.wait(lck); // 等待队列不满
//}
// 等价于上面的while
// 满足第二项的pred才能退出while
// 等1s没出来就退出返回
if (!notFull_.wait_for(lck, std::chrono::seconds(1), [&]()->bool {
return taskQue_.size() < taskQueMaxThreadhold_ }))
{
std::cerr << "task queue is full, submit task fail" << std::endl;
return;
}
// 如果有空余,把任务放入任务队列中
taskQue_.emplace(sp);
taskSize_++; // ???
// 任务队列不空,唤醒notEmpty_的wait,即通知消费者消费
notEmpty_.notify_all();
}
线程执行任务的函数
void ThreadPool::threadFunc()
{
/*std::cout << " begin threadFunc tid:" << std::this_thread::get_id() << std::endl;
std::cout << " endthreadFunc tid:" << std::this_thread::get_id() << std::endl;*/
for (;;)
{
std::shared_ptr<Task> task;
{
// 获取锁
std::unique_lock<std::mutex> lck(taskQueMtx_);
std::cout << "tid:" << std::this_thread::get_id() << "尝试获取任务..." << std::endl;
// 等待notEmpty_条件
notEmpty_.wait(lck, [&]()->bool {
return taskQue_.size() > 0; });
std::cout << "tid:" << std::this_thread::get_id() << "获取任务成功..." << std::endl;
// 从任务队列中取一个任务出来
task = taskQue_.front();
taskQue_.pop();
taskSize_--;
// 若依然有剩余任务,继续通知其他线程执行任务
if (taskQue_.size() > 0)
{
notEmpty_.notify_all();
}
// 取出一个任务进行通知 生产者可以进行生产任务
notFull_.notify_all();
} // 只需要对taskQue_及相关临界资源操作才加锁,执行不需要加锁
// 当前线程负责执行这个任务
if (task != nullptr)
{
task->run();
}
}
}
相关测试
#include <iostream>
#include <chrono>
#include "threadpool.h"
class MyTask : public Task
{
public:
void run()
{
std::cout << "tid:" << std::this_thread::get_id() << " begin!" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "tid:" << std::this_thread::get_id() << " end!" << std::endl;
}
};
int main()
{
ThreadPool pool;
pool.start(4);
// 提交10个任务
pool.submitTask(std::make_shared<MyTask>());
pool.submitTask(std::make_shared<MyTask>());
pool.submitTask(std::make_shared<MyTask>());
pool.submitTask(std::make_shared<MyTask>());
pool.submitTask(std::make_shared<MyTask>());
pool.submitTask(std::make_shared<MyTask>());
pool.submitTask(std::make_shared<MyTask>());
pool.submitTask(std::make_shared<MyTask>());
pool.submitTask(std::make_shared<MyTask>());
pool.submitTask(std::make_shared<MyTask>());
getchar();
return 0;
}
分析
我们的任务队列大小已经设置为4,每个任务要sleep 5秒,刚开始4个任务放入任务队列,被线程取走执行,然后又能放入4个任务,此时任务队列已满,但是此时前面执行的4个任务都没执行完。剩余2个任务试图放入任务,阻塞1s后便失败。