当一些异步的任务的时候,使用C++来创建线程来做任务的时候,
可以引用std::thread这个库
使用方法如下,创建一个线程,里面通过std::bind来绑定方法任务。
std::thread thread = std::thread(std::bind(&类名::方法名,this 参数);
这只是初始化线程
thread.join()
等着线程执行完成之后,主线程才能执行下去,此时主线程会立刻释放子线程占用的资源
thread.detach()
主线程不需要等待子线程执行完成,主线程和子线程分离
这是简单的线程调用,而C++中并没封装好线程池给我们使用。这里网上找了一个例子,可以简单看看注释。
#include <functional>
#include <vector>
#include <thread>
#include <mutex>
#include <atomic>
#include <queue>
#include <condition_variable>
#include <future>
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
namespace std { //声明std的作用域
#define MAX_THREAD_NUM = 256
class MagicThreadPool {
public:
//内联函数,
inline MagicThreadPool(unsigned short size = 4) : stoped{false} {
//线程池大小
idlThrNum = size < 1 ? 1 : size;
for (size = 0; size < idlThrNum; ++size) { //初始化线程数量
// 只有一次构造函数,不调用拷贝构造函数,速度最快
pool.emplace_back(
[this] { // 工作线程函数
while (!this->stoped) {
//声明任务
std::function<void()> task;
{ // 获取一个待执行的 task
std::unique_lock<std::mutex> lock{this->m_lock};// unique_lock 相比 lock_guard 的好处是:可以随时 unlock() 和 lock()
this->cv_task.wait(lock,
[this] {
return this->stoped.load() ||
!this->tasks.empty();
}
); // wait 直到有 task
if (this->stoped && this->tasks.empty())
return false;
task = std::move(this->tasks.front()); // 取一个 task
this->tasks.pop();
}
idlThrNum--;
//运行任务
task();
idlThrNum++;
}
}
);
}
}
//析构函数
inline ~MagicThreadPool() {
//停止全部任务
stoped.store(true);
cv_task.notify_all(); // 唤醒所有线程执行
for (std::thread &thread : pool) {
//thread.detach(); // 让线程“自生自灭”
if (thread.joinable())
thread.join(); // 等待任务结束, 前提:线程一定会执行完
}
}
//模板,需要声明类的类型,自动匹配返回值
template<class F, class... Args>
auto commit(F &&f, Args &&... args) -> std::future<decltype(f(args...))> {
//直接停止任务
if (stoped.load()) // stop == true ??
throw std::runtime_error("commit on ThreadPool is stopped.");
using RetType = decltype(f(
args...)); // typename std::result_of<F(Args...)>::type, 函数 f 的返回值类型
//自动返回值
auto task = std::make_shared<std::packaged_task<RetType()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
); // wtf !
std::future<RetType> future = task->get_future();
{ // 添加任务到队列
std::lock_guard<std::mutex> lock{
m_lock};//对当前块的语句加锁 lock_guard 是 mutex 的 stack 封装类,构造的时候 lock(),析构的时候 unlock()
tasks.emplace( //放入任务到任务池
[task]() { // push(Task{...})
(*task)();
}
);
}
cv_task.notify_one(); // 唤醒一个线程执行
return future;
};
//空闲线程数量
int idlCount() { return idlThrNum; }
private:
using Task = std::function<void()>;
//线程池
std::vector<std::thread> pool;
//任务队列
std::queue<Task> tasks;
//同步锁
std::mutex m_lock;
std::condition_variable cv_task;
std::atomic<bool> stoped;
std::atomic<int> idlThrNum;
};
}
#endif
使用方式
pool->commit(类名::方法名,参数);
这里注意一定不要这里是一个MagicThreadPool.h文件,千万别想因为代码好看分成两个h和cpp来写。
因为cpp将会编译好的代码,是无法更改的,无法进行模板在线程调用方法中的参数推导。会无法编译通过。
如果想看具体的流程可以看我MagicCamera3的代码
地址是MagicCamera3 https://github.com/cangwang/MagicCamera3,欢迎大家下载和点赞,如果有问题,也可以进我的组件化群1和群2,来讨论问题。
网友评论