目录
进程和线程
- 进程:程序(应用程序,可执行文件)一次执行,便开启了一个进程;
进程是 CPU 独立分配资源的单位
- 线程:进程中的一个实体,被系统独立分配和调度的基本单位
线程是 CPU 可执行调度的最小单位,进程本身并不能获取 CPU 时间,只有它的线程可以。
线程参与操作系统的调度,参与CPU的竞争,得到分配的时间片,获得处理机(CPU)运行。
进程负责获取操作系统分配的资源,如内存。
并发和并行
- 并发:同一时段内可以交替处理多个操作,强调同一时段内交替发生;
- 并行:同一时刻内同时处理多个操作,强调同一时刻同时发生。
C++11 线程
多线程支持库
C++ 标准并没有提供对多进程并发的原生支持,所以 C++ 的多进程并发要靠其他 API。
-
<thread>
: 提供线程创建及管理的函数或类接口; -
<mutex>
: C++11 互斥量 Mutex。多线程环境下避免竞争同一个公共资源; -
<condition_variable>
: 允许一定量的线程等待(可定时)被另一线程唤醒,然后再继续执行; -
<future>
: 提供了一些工具来获取异步任务(即在单独的线程中启动的函数)的返回值,并捕捉其所抛出的异常; -
<atomic>
: 为细粒度的原子操作(不能被处理器拆分处理的操作)提供组件,允许无锁并发编程。
std::thread 类成员函数
-
get_id
: thread::id 线程 ID 获取; -
joinable
: 检查线程是否可被 join 。检查线程是否标识 active 的可行性编程;缺省构造的、已完成 join 的、已经 detach 的线程都不是 joinable 。
-
join
: 函数关联并阻塞线程,等待该线程执行完毕后继续; -
detach
: 函数解除关联使线程可以和主线程并发执行,若主线程执行完毕退出则关联线程也将自动退出; -
native_handle
: 返回与 std::thread 具体实现相关联的线程句柄; -
swap
: 交换两个线程对象所代表的底层句柄; -
operator
: 移动线程对象。
命名空间 this_thread 声明在 <thread>
头文件中,可对当前调用者线程的 ID 的获取:
-
get_id
: 获取当前调用者线程的ID; -
yield
: 将调用者线程跳出运行状态,重新交给操作系统进行调度,即当前线程放弃执行,操作系统调度另一线程继续执行; -
sleep_until
: 将线程阻塞至某个时间点(time point); -
sleep_for
: 将线程阻塞某个指定时间片(time span),不过由于线程调度等原因,实际休眠可能比 sleep_duration 所表示的更长。
总结
-
判断一个 thread 对象是否关联某个线程,使用 joinable() 接口,返回 true 则表明该对象关联着某个线程(即使该线程已经执行结束);
-
joinable 的对象析构前必须调用 join() 等待结束,或者调用 detach() 解除关联;
-
正在执行的线程从关联的对象 detach() 后会自主执行直至结束,对应的对象变成不关联任何线程的对象,joinable() 返回 false;
-
std::thread 没有拷贝构造和拷贝复制,没有多个对象表示同一执行线程;
-
默认构造的、被移动后的、detach 或 join 后的线程对象不关联任何线程。
示例
- 可调用函数,时间段阻塞(线程暂停)
// 时间段阻塞线程
void f1()
{
std::cout << "hello" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
// 调用
std::thread t1(f);
t1.join();
- 函数重载,带参数
// 可调用函数重载,线程带参数
class Task
{
public:
void operator()(int i)
{
std::cout << "参数:" << i << std::endl;
}
};
// 调用
Task task;
std::thread t3(task, i);
t3.join();
- 线程传递引用
void f2(int &i)
{
std::cout << "引用 :" << (i+=4) << std::endl;
}
// 调用
std::thread t4(f2, std::ref(i));
t4.join();
- 转移线程所有权
std::thread t5(std::move(t4));
- 线程 ID
// 线程调用函数内部获取
// function(){std::thread::id this_id = std::this_thread::get_id();}
// 线程获取
std::thread::id id = t5.get_id();