读书笔记《C++并发编程实战》(4) - 同步并发操作
等待事件: 条件变量等待: std::condition_variable/std::condition_variable_any,前者配合std::mutex以及std::unique_lock、std::lock_guard, 后者可配合类似互斥体(包括互斥体)的类型工作,不过因其内部持有std::mutex对象成员的锁保护,性能和大小上会有一定的代价。 条件变量使用wait等待条件成立以便继续执行,notify_one通知任意某个正在执行wait的等待线程可继续执行,notify_all通知所有的等待 线程可继续执行。 future等待: 一种一次性事件;也即当该等待future变为就绪状态,则不可复位其状态。 提供两种future,一种唯一future(std::future)、另一种共享future(std::shared_future),前者的实例指向一个事件,后者的多个共享 实例可关联同一事件。对于后者当事件就绪时,所有实例均变为就绪状态。 异步获取后台计算结果: std::async启动一个异步任务,其返回一个std::future对象,该对象将持有函数的返回值;此时调用 该对象的get接口(线程将被阻塞直到该future对象就绪并获取返回值)。std::future模板参数即为获取类型返回的值。 std::async重载版本支持指定启动方式,std::launch::deferred/std::launch::async,前者为延迟直到调用wait/get时运行,后者立即开启 新的线程运行,若为组合,则根据平台具体实现来选择。 std::async可以启动一个异步任务,此外std::packaged_task<>、std::promise<>也可以实现启动并行运行的任务。 std::async是更高层次上的异步操作,使我们不用关注线程创建内部细节,能方便的获取异步执行状态和结果。 std::packaged_task<>将一个future绑定到一个函数或是可调用对象上,模板参数为该函数签名。std::packaged_task重载了operator(); 即可调用执行任务,此后在其他地方调用该对象的get_future接口,即可获取到关联的std::future对象;相对std::promise<>,前者保存的 是一个可调用函数或对象(以实现异步操作),后者是一个共享状态值;共同点是均通过get_future获取到关联的future对象,以获取最后的 调用函数或对象的返回值或者设置的值。 std::promise<>一个异步服务提供者,通过设置值得方式,使得与之关联的std::future对象来读取设置值。promise中set_value接口 或者设置异常时set_exception可使得std::future变为就绪状态。同样的std::promise接口get_future获取到关联的future对象。 std::future可保持值或者异常。这样在不同地方设置promise值,另一个地方通过future对象获取该设置值。 共享std::shared_future: std::shared_future可有多个实例引用同一个事件的相关状态,具有可复制性,std::future具有可移动性,也即移动后其valid将返回无效。 而被赋值移动的future对象变得有效,此外std::shared_future可多次调用get获取共享状态。std::future可转为std::shared_future对象,被 转移后std::future也会变得无效。 基于时间限制的等待: chrono:时间库,主要提供了时间概念相关的模板类或者工具。主要有:时间段duration、时间点time_point、时钟clock; 时钟clock:system_clock(系统时钟(不匀速,可变))、steady_clock(稳定/均速时钟、不可变)、high_resolution_clock(高精度时钟, 可能为均速时钟或系统时钟)。 时间段duration:duration<type T, std::ratio<N,M>>,模板参数T为存储时间类型,参数ration则为分数表示每个时间段单位表示多少秒,其中 N/M的值表示多少秒为一个时间段,如<3600,1>表示3600秒也即1小时为一个时间段,<1,1000>表示0.001秒即1毫秒为一个时间段,标准库已提供 一些常用的预定义时间段如std::chrono::milliseconds、std::chrono::hours等。 工具转换函数std::chrono::duration_cast<>可实现时间段之间的显式转换。 时间点time_point:std::chrono::time_point。 C++中接受超时相关的函数主要有: std::this_thread::sleep_for,std::this_thread::sleep_until; std::condition_variable::wait_for,std::condition_variable::wait_until; std::condition_variable_any::wait_for,std::condition_variable_any::wait_until; std::timed_mutex::try_lock_for,std::timed_mutex::try_lock_until; std::unique_lock::unique_lock,std::unique_lock::try_lock_for,std::unique_lock::try_lock_until; std::future::wait_for,std::future::wait_until; std::shared_future::wait_for,std::shared_future::wait_until; 避免共享可变数据的一些方法: 采用函数式编程(FP)、通信顺序处理(CSP/MPI消息传递接口); 一些操作同步简化代码: 带有future的函数式编程:借助std::future、std::async或者packaged_task与std::thread可实现并发操作。 具有消息传递的同步操作:采用多线程实现不同任务的划分执行,线程间不再共享数据,线程间的通信通过共享的消息队列实现, 以此多线程来划分关注点,简化设计和实现并发系统任务。