C++ Concurrency in Action 读书笔记一:thread的管理

为避免混淆,用thread表示std::thread及其对象实例,用线程表示操作系统概念下的线程

Chapter 2 thread的管理

2.1 thread的创建(构造函数)

a. 默认构造函数

default: thread() noexcept;

创建一个placeholder,不和任何线程关联。其使用场景如定义一个thread数组。可以在之后通过thread& operator=( thread&& other ) noexcept来赋予值以和线程关联

b. Move构造函数

thread (thread&& other) noexcept;

c. 初始化构造函数

template<class Function, class...Args>
explicit thread(Function&& f, Args&&...args);

常用的构造函数,在创建对象的时候传入function及其参数,从而和线程关联

d. 拷贝构造函数

thread(const thread&) = delete;

thread对象不可拷贝

2.2 join:等待线程执行完成

join也会清理和线程有关的所有内存。join返回后thread不再与任何线程关联,joinable()将返回false。每个线程只能调用一次join

异常可能使程序在join被调用前结束,为了避免这种情况,需要在catch中也调用join。但 try-catch 的方式过于繁琐,而且会打乱作用域。因此如果确实有要保证在所有退出路径均join的需求,可以采用 RAII 机制,封装一个 thread_guard 类,在其析构函数中处理

2.3 detach:后台线程

thread对象调用detach将使与之关联的线程在后台运行,且断绝了任何能与之通信的手段,无法再通过thread对象来引用它,也因此无法被join

被 detach 的线程又叫做 daemon 线程

thread对象是否可被 detach 和其是否可以 join需满足相同的条件:必须有线程与之关联,体现在joinable()必须返回true

2.4 thread参数传递

构造thread对象时在传入 callable 之后紧接着传入其所需参数

参数被拷贝到可以被新创建的线程访问到的内部存储中,然后作为右值传给 callable,如同临时变量一样

如果传参以来隐式转型,则结果可能并非所料。如参数为string const&,传入的为char buff[LEN]时,虽然看起来是buf会隐式转型为string const,然后再传给 callable,但实际上传参时是 as is,即不加处理、先将传入的参数(此处是 buf(指针/数组名))拷贝到内部存储,此时若thread对象被detach,则buf指向的存储空间被清理,而此时 callable 的参数可能未来得及构造出来,从而会出现未定义的行为

直接传 non-const reference 的话会编译出错,因为构造函数接受的参数类型为右值,如果想传引用,需用std::ref

如果参数类型不能被拷贝只能被 move,则传参后控制权会转移

2.5 thread ownership的转移

thread对象实例可以被 move,可以被 move 构造

不可 move 给已经同线程关联的thread

2.6 std::thread::hardware_concurrency():一般为CPU核数,但只是 hint 值,也可能为0

2.7 thread的标识

线程标识类型:std::thread::id,可进行比较,可哈希,但其值没有语义涵义(无意义)

调用thread对象实例的get_id()方法获取 id。若未与线程相关联,则返回默认构造的 id,表示 not any thread

当前线程的 id 可以通过std::this_thread::get_id()获取 id

posted on 2019-08-08 23:41  westwindrest  阅读(359)  评论(0编辑  收藏  举报