thread是计算的概念在计算机硬件层面的抽象。C++标准库 thread的设计目标是与操作系统线程形成一对一映射。当程序中多个任务需要并发进行时,我们就可以使用 thread在一个多处理单元(“核心”)的系统上, thread可以充分利用这些单元。所有 thread工作于同一个地址空间中。如果你希望硬件能防止数据竞争,则应使用进程。 thread间不共享栈,因此局部变量不会产生数据竞争问题,除非你不小心将一个局部变量的指针传递给其他thread。我们要特别小心 lambda中的引用方式的上下文绑定(见11.4.3节)。深思熟虑地、小心地共享栈内存空间很有用,也很常见。例如,我们可能将一个局部数组的不同部分传递给一个并行排序函数。
如果一个 thread不能继续前进(比如,因为它遇到了一个其他 thread所拥有的 mutex),我们称它处于阻塞( blocked)或睡眠( asleep)状态。
| thread(iso.30.3.1) | |
|---|---|
| id | thread标识符类型 |
| native_handle_type | 系统线程句柄类型;由具体C++实现定义(iso.30.2.3) |
| thread t{}; | 默认构造函数:创建一个(还)没有任务的thread;不抛出异常 |
| thread t{t2}; | 移动构造函数:不抛出异常 |
| thread t{f,args}; | 构造函数:在一个新的thread上执行f(args);显式构造函数 |
| t.~thread(); | 析构函数;若t.joinable(),则terminate();否则无异常 |
| t=move(t2); | 移动复制:若t.joinable(),则terminate();不抛出异常 |
| t.swap(t2) | 交换t和t2的值;不抛出异常 |
| t.joinable() | 某个线程的执行与t关联?t.get_id()!=id{}?;不抛出异常 |
| t.join() | 将t与当前线程结合;即,阻塞当前thread直至t完成;若检测到死锁,抛出syetem_error(如t.get_id()==this_thread::get_id());若t.id()==id{},抛出system_error |
| t.detach() | 确保t不在表示任何系统线程;若t.id!=id{}抛出system_error |
| x=t.get_id() | x为t的id;不抛出异常 |
| x=t.native_handle() | x为t的本机句柄(类型为native_handle_type) |
| n=hardware_concurrency() | n为硬件处理单元树(0表示”不知道”);不抛出异常 |
| swap(t,t2) | t.swap(t2);不抛出异常 |
一个 thread表示一个系统资源,一个系统线程( system thread),甚至可能有专用硬件:
因此, thread可以移动但不能拷贝。
作为一个源被移动后, thread就不再表示一个计算线程了。特别是,它不能被jon()了。
操作thread::hardware_concurrency(报告硬件支持多少个任务同时执行。其具体含义依赖于机器体系结构,但通常小于操作系统提供的线程数(例如,通过时间多路复用或时间分片),有时大于处理器数或“核心数”。例如,我的双核小笔记本报告有四个硬件线程(它使用了超线程( hyper-threading)技术)。
