异步不需要等待当前任务完成,就可以继续执行后续任务的处理方式。

async

std::async用于异步执行任务。它返回一个std::future对象,可以通过future.get()获取结果。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <future>

int add(int a, int b) {
return a + b;
}

int main() {
std::future<int> result = std::async(add, 3, 4);

std::cout << result.get() << std::endl;

return 0;
}

输出:

1
7

async 的启动策略

std::async 有两种常用启动策略:

1
2
std::launch::async
std::launch::deferred

std::launch::async

立即创建异步任务,通常会在新线程中执行。

1
2
3
auto fut = std::async(std::launch::async, [] {
return 100;
});

std::launch::deferred

延迟执行任务。

只有当调用 get()wait() 时,任务才会在当前线程执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <future>
#include <thread>

int main() {
auto fut = std::async(std::launch::deferred, [] {
std::cout << "执行线程 ID: "
<< std::this_thread::get_id()
<< std::endl;
return 100;
});

std::cout << "主线程 ID: "
<< std::this_thread::get_id()
<< std::endl;

std::cout << fut.get() << std::endl;

return 0;
}

如果不指定策略:

1
std::async(func);

实现可以自行选择是异步执行还是延迟执行。

如果希望一定异步执行,建议写:

1
std::async(std::launch::async, func);

future

std::future表示一个未来可获得的结果。

常用方法:

1
2
3
4
5
get();
wait();
wait_for();
wait_until();
valid();

get

获取异步任务结果。

1
int value = fut.get();

注意:

get() 只能调用一次。

调用后 future 不再拥有结果。

wait

等待任务完成,但不获取结果。

1
fut.wait();

wait_for

等待一段时间,检查任务是否完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <future>
#include <chrono>
#include <thread>

int slowTask() {
std::this_thread::sleep_for(std::chrono::seconds(2));
return 42;
}

int main() {
auto fut = std::async(std::launch::async, slowTask);

auto status = fut.wait_for(std::chrono::seconds(1));

if (status == std::future_status::ready) {
std::cout << "结果: " << fut.get() << std::endl;
} else {
std::cout << "任务尚未完成" << std::endl;
std::cout << "稍后结果: " << fut.get() << std::endl;
}

return 0;
}

promise

std::promise 用于在线程之间传递结果。

一个线程设置值,另一个线程通过 future 获取值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <thread>
#include <future>

void worker(std::promise<int> p) {
int result = 10 + 20;
p.set_value(result);
}

int main() {
std::promise<int> p;
std::future<int> fut = p.get_future();

std::thread t(worker, std::move(p));

std::cout << "结果: " << fut.get() << std::endl;

t.join();

return 0;
}

注意:

std::promise 不能复制,只能移动。

promise 传递异常

如果工作线程发生异常,可以使用 set_exception() 传递给 future。

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
#include <iostream>
#include <thread>
#include <future>
#include <exception>

void worker(std::promise<int> p) {
try {
throw std::runtime_error("计算失败");
p.set_value(100);
} catch (...) {
p.set_exception(std::current_exception());
}
}

int main() {
std::promise<int> p;
std::future<int> fut = p.get_future();

std::thread t(worker, std::move(p));

try {
std::cout << fut.get() << std::endl;
} catch (const std::exception& e) {
std::cout << "捕获异常: " << e.what() << std::endl;
}

t.join();

return 0;
}

packaged_task

std::packaged_task 可以把一个可调用对象包装成异步任务。

它内部会绑定一个 future

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <future>
#include <thread>

int square(int x) {
return x * x;
}

int main() {
std::packaged_task<int(int)> task(square);

std::future<int> fut = task.get_future();

std::thread t(std::move(task), 6);

std::cout << "结果: " << fut.get() << std::endl;

t.join();

return 0;
}

输出:

1
36

适合场景:

  • 任务队列
  • 线程池
  • 延迟执行任务
  • 将函数和结果 future 分离管理

shared_future

普通 std::futureget() 只能调用一次。

如果多个线程都需要读取同一个结果,可以使用 std::shared_future

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
#include <iostream>
#include <future>
#include <thread>
#include <vector>

int compute() {
return 123;
}

void reader(std::shared_future<int> sf, int id) {
std::cout << "线程 " << id
<< " 获取结果: " << sf.get()
<< std::endl;
}

int main() {
std::future<int> fut = std::async(std::launch::async, compute);

std::shared_future<int> sf = fut.share();

std::vector<std::thread> threads;

for (int i = 0; i < 3; ++i) {
threads.emplace_back(reader, sf, i);
}

for (auto& t : threads) {
t.join();
}

return 0;
}

async、thread、promise 的区别

工具 主要作用 返回值 管理难度
std::thread 创建线程执行任务 不直接返回 较高
std::async 异步执行任务 通过 future 返回 较低
std::promise 在线程间传递结果 配合 future 中等
std::packaged_task 包装任务 配合 future 中等

选择建议

简单异步计算

使用:

1
std::async

需要手动控制线程生命周期

使用:

1
std::thread

一个线程向另一个线程传递结果

使用:

1
std::promise + std::future

构建任务队列或线程池

使用:

1
std::packaged_task