C++ 从入门到精通之十三

大纲

C++ 并发编程

std::future

这里不再介绍 std::future 的基础使用,而是重点介绍 std::future 进阶使用的内容。

wait_for()

std::future::wait_for() 用于等待异步任务在指定时间内完成,它不会获取任务结果,而是阻塞当前线程一段时间,并通过返回值表示任务当前状态。返回值类型为 std::future_status,包含三种状态:ready 表示异步任务已完成,可以通过 get() 获取结果;timeout 表示等待时间结束,但任务仍未完成;deferred 表示任务采用延迟执行策略,需要调用 get()wait() 时才会执行。wait_for() 适合用于超时检测、周期性检查异步任务状态等场景,常与 std::asyncstd::promisestd::packaged_task 等异步机制配合使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <chrono>
#include <future>
#include <iostream>
#include <thread>

int process(int milliseconds) {
std::cout << "process() start, current thread id " << std::this_thread::get_id() << std::endl;
// 模拟业务处理耗时
const std::chrono::milliseconds ms(milliseconds);
std::this_thread::sleep_for(ms);
std::cout << "process() end, current thread id " << std::this_thread::get_id() << std::endl;
// 返回业务处理结果
return 5;
}

int main() {
std::cout << "main() run, thread id " << std::this_thread::get_id() << std::endl;
// 启动一个子线程,第二个参数是线程函数的参数
std::future<int> result = std::async(std::launch::async, process, 5000);
std::cout << "continue ..." << std::endl;

// 等待指定时间
std::future_status status = result.wait_for(std::chrono::seconds(2));

// 判断 Future 的状态(任务执行状态)
if (status == std::future_status::timeout) {
std::cout << "future timeout" << std::endl;
}
else if (status == std::future_status::ready) {
std::cout << "future ready" << std::endl;
}else if (status == std::future_status::deferred) {
std::cout << "future deferred" << std::endl;
} else {
std::cout << "future unknow status" << std::endl;
}

std::cout << "main() end, thread id " << std::this_thread::get_id() << std::endl;

// main 线程执行完成后,程序不会立即结束;因为 std::future 对象析构时,会等待对应的异步任务执行完成
return 0;
}

程序运行的结果如下:

1
2
3
4
5
6
main() run, thread id 1
continue ...
process() start, current thread id 2
future timeout
main() end, thread id 1
process() end, current thread id 2

特别注意

  • std::future::wait_for() 可以用于在指定时间内等待异步任务完成,并通过返回值 std::future_status 判断任务当前状态。需要注意的是,wait_for() 本身不会影响异步任务的执行,也不会取消任务,只是用于检测任务是否在指定时间内完成
  • 当使用 std::async(std::launch::async, ...) 创建异步任务时,即使 wait_for() 返回 timeout,表示任务仍在执行,异步线程也会继续运行。若对应的 std::future 对象生命周期结束,在析构阶段会等待异步任务执行完成后再退出程序。因此,wait_for() 适用于超时检测、任务状态轮询等场景,但不能用于终止正在执行的异步任务。

std::shared_future

std::shared_future 的概述

  • 概述:

    • std::shared_future 是 C++ 11 引入的异步结果共享机制,用于允许多个线程或多个对象共享同一个异步结果
    • 它与 std::future 类似,都可以获取异步任务的结果,但 std::future 通常只能由一个对象获取结果,而 std::shared_future 支持多个对象重复访问同一个结果。
  • 特点:

    • 异步结果共享:多个 std::shared_future 对象可以共享同一个异步结果。
    • 支持重复获取:可以多次调用 get() 获取相同的结果,而 std::futureget() 通常只能调用一次。
    • 线程间共享结果:适合将同一个异步结果传递给多个线程。
    • 支持异常共享:如果异步任务产生异常,多个 std::shared_future 对象调用 get() 时都可以获得该异常。
    • 支持拷贝std::shared_future 支持拷贝,多个对象可以共享同一个共享状态。
    • 可由 std::future 转换:可以通过 std::future::share()std::future 转换为 std::shared_future,转换后原 std::future 不再有效。
  • 常用成员函数:

    • get():获取异步任务的结果,可以被多次调用。
    • wait():等待异步任务完成。
    • wait_for():等待指定时间,并返回任务状态。
    • wait_until():等待到指定时间点,并返回任务状态。
    • valid():判断当前 shared_future 是否关联有效的共享状态。
  • std::future 的区别:

    组件作用
    std::future独占异步结果,通常只能获取一次结果
    std::shared_future共享异步结果,可以被多个对象、多个线程获取

总结

std::shared_future 是一种可共享、可重复获取的异步结果对象,主要解决 std::future 结果只能由单个对象获取的问题。它适合需要将同一个异步结果提供给多个线程或多个消费者的场景。

std::shared_future 的使用