马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
第二章 线程管控
std::thread 简介
构造和析构函数
- /// 默认构造
- /// 创建一个线程,什么也不做
- thread() noexcept;
- /// 带参构造
- /// 创建一个线程,以 A 为参数执行 F 函数
- template <class Fn, class... Args>
- explicit thread(Fn&& F, Args&&... A);
- /// 拷贝构造(不可用)
- thread(thread& Other) noexcept = delete;
- /// 移动构造
- /// 移交线程的归属权
- thread(thread&& x) noexcept;
- /// 析构函数
- ~thread();
复制代码 常用成员函数
- /// 等待线程结束并清理资源(会阻塞)
- void join();
- /// 返回线程是否可以执行 join() 成员函数
- bool joinable();
- /// 将线程与调用其的线程分离,彼此独立执行(此函数必须在线程创建时立即调用,
- /// 且调用此函数会使其不能被join)
- void detach();
- /// 获取线程id
- std::thread::id get_id();
- /// 见移动构造函数
- /// 如果对象是 joinable 的,那么会调用 std::terminate() 结果程序
- thread& operator=(thread&& Other) noexcept;
复制代码 使用线程类完成线程的基本管控
发起线程
- 线程通过构建std::thread对象而启动,该对象指明线程要运行的任务。
- void do_some_work();
- std::thread my_thread(do_some_work);
复制代码- class background_task{
- public:
- void operator()() const{
- do_something();
- do_something_else();
- }
- };
- background_task f;
- std::thread my_thread1(f);
- // 使用匿名函数对象
- // std::thread my_thread2(background_task());这样写会出错,
- // 编译器会解释成函数声明,返回值为 std::thread, 函数名为 my_thread2,
- // 函数参数为函数指针类型 background_task (*)(void), 因此改为如下两种方式:
- std::thread my_thread2((background_task()));
- // 采用新式的统一初始化语法(uniform initialization syntax,又名列表初始化)
- std::thread my_thread2{background_task()};
复制代码 等待线程完成
一旦启动了线程,我们就需明确是要等待它结束(与之汇合 join()),还是任由它独自运行(与之分离 detach())- std::thread my_thread1(f);
- // ...
- my_thread1.join();// 等待线程结束并清理资源
复制代码❗❗❗ 同一个线程的 .join() 方法不能被重复调用,否则程序会 abort()
对 thread 封装——thread_guard
基于 RAII 原理,对 std::thread 进行封装
[code]// std::thread 封装(基于RAII)class thread_guard{ thread& m_thread;public: explicit thread_guard(thread& t):m_thread(t){} ~thread_guard() { // 检查是否joinable是有必要的,重复 join() 会出错 if (m_thread.joinable()){ m_thread.join(); } } // C++11 "=delete" 标记,声明拷贝构造和复制赋值操作为被删除的函数 // 防止拷贝导致重复调用 join() thread_guard(thread_guard const&) = delete; thread_guard& operator=(thread_guard const&) = delete;};int main(){ thread t([] {cout
|