最近没更新博客,今天来写下c++线程库的基本原理,直接上代码
思路:
1 初始化线程
2 线程上锁 -> 然后解除锁的占用 -> 等待信号通知
3 某个线程被通知到后 -> 获取锁 -> 锁获取后取任务队里第一个任务函数 -> 解除锁 -> 执行任务 -> 继续第二步操作
关键点:信号通知函数 notify_one() ,只会通知等待区中的一个,让其来获取锁, 避免惊群事件。
该线程池只支持空值返回的任意参数的函数(lambda),没有异常处理,算是个基本雏形吧。看注释就能理解。
#include <vector>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <functional>
using namespace std;
class ThreadPool
{
public:
ThreadPool(size_t threads)
{
// 初始指定数量的线程
for (size_t i = 0; i < threads; ++i)
{
// emplace_back避免拷贝插入
m_works.emplace_back([this] {
while (true)
{
function<void()> task;
{
// 申请队列互斥锁
unique_lock<mutex> lock(this->m_mutex);
// 释放锁的占用,等待条件通知, 强制停止或者有任务
this->m_condition.wait(lock, [this]
{
return this->m_stop || !this->m_queueTasks.empty();
});
// 线程池退出,并且任务队列中没有任务 线程退出
if (this->m_stop && this->m_queueTasks.empty())
{
break;
}
// 取任务队中第一并弹出
task = move(this->m_queueTasks.front());
this->m_queueTasks.pop();
// 锁的作用域范围结束,释放互斥锁
}
// 运行任务
task();
}
});
}
}
~ThreadPool()
{
{ // 申请锁,置stop
unique_lock<mutex> lock(m_mutex);
m_stop = true;
}
// 通知所有临界区的等待结束
m_condition.notify_all();
// 等待所有线程退出
for (thread& t : m_works)
{
t.join();
}
}
template<class F, class... Args>
void addTask(F&& f, Args&&... args)
{
// bind函数地址及参数
auto task = bind(forward<F>(f), forward<Args>(args)...);
{
// 申请锁
unique_lock<mutex> lock(m_mutex);
// 强制停止不能再加任务
if (m_stop)
{
cout << "pool is stop!" << endl;
return;
}
// 添加
m_queueTasks.emplace(task);
// 锁释放
}
// 在等待区的一个被通知,避免惊群
m_condition.notify_one();
}
private:
vector<thread> m_works; // 线程集合
queue<function<void()>> m_queueTasks; // 等待运行的任务队列
mutex m_mutex; // 任务队列的互斥锁
condition_variable m_condition; // 条件变量
bool m_stop; // 终止所有线程
};
void testTaskInt(int i)
{
cout << "task int" << i << " process!" << endl;
}
void testTaskString(string s)
{
cout << "task string " << s.c_str() << " processs!" << endl;
}
int _tmain()
{
{
ThreadPool pool(4);
// 任务函数bind参数
pool.addTask(&testTaskInt, 1);
pool.addTask(&testTaskString, "hello world!");
// lamda函数
int i = 999;
string s = "hello lamda";
pool.addTask([i, s]
{
cout << "task lamda " << i << s.c_str() << "process!" << endl;
});
this_thread::sleep_for(chrono::seconds(10));
}
// pool 销毁
return 0;
}