future/promise
1 来源
需要从线程中返回异步任务结果情形时,c++11之前:
使用指针在线程间共享数据。
传递一个指针到新的线程中,该线程在其中设置数据,直到主线程继续等待使用条件变量。当新线程设置数据并通知条件变量时,主线程将唤醒并从指针处获取数据;
示例:
void fun(int x, int y, int *ans)
{
std::cout << "proc thread: " << std::hex << std::this_thread::get_id() << std::endl;
*ans = x + y;
}
void test_future()
{
std::cout << "main thread: " << std::hex << std::this_thread::get_id() << std::endl;
int a{10};
int b{8};
int sum{};
std::thread t(fun, a, b, &sum);
t.join();
std::cout << "sum: " << sum << std::endl;
return;
}
std::future
C++11提供future类模板,future对象提供访问异步操作结果的机制。
分类
唯一期望(unique futures, std::future<>)实例只能与一个指定事件相关联;
共享期望(shared futures, std::shared_future<>)实例能关联多个事件
一个std::future对象在内部存储一个将来会被某个provider赋值的值,并提供一个访问该值的机制,通过get()成员函数实现。在get可用前访问,会被阻塞,直至该值可用。
2 std::future
一个有效的std::future对象通常由以下三种Provider创建,并和某个共享状态相关联。Provider可以是函数/类,分别为:
std::async函数
std::promise::get_future
std::packaged_task::get_future
C++11提供的future头文件中包含:
Providers类:std::promise, std::package_task
Futures类:std::future, shared_future
Providers函数:std::async
Other: std::future_error, std::future_errc, std::future_status, std::lauch
std::future提供默认构造函数和移动构造函数,禁止拷贝构造函数。
成员函数:
std::future::valid()
检查future对象是否拥有共享状态,参照构造函数只有两种可用,默认构造创建的future对象不具有共享状态,即valid() = false,除非是被move赋值;移动构造的future对象往往拥有共享状态,在get()前需要确认共享状态标志是否设置为ready。
std::future::get()
阻塞式获取共享状态的值,若调用get时,状态不是ready,则阻塞至ready。
std::future::wait()
等待共享状态标志变为ready,此前线程一直阻塞
std::future::wait_for()
等待一段时间,之后即使共享状态不为ready,一样会返回。
std::future::wait_until()
参考绝对时间点
std::future::share()
返回一个std::shared_future对象,调用该函数后,future对象不和任何共享状态相关联,也就不再是valid
[注] wait_for & wait_until返回值
future_status::ready
future_status::timeout
future_status::deferred
模板参数是void情景
在C++中,std::future
是一个模板类,它用于从异步任务中检索结果。std::future
的模板参数是用于指定异步任务返回值的类型。当异步任务不返回任何值(即返回类型为 void
)时,你仍然可以使用 std::future
,但此时 std::future
的模板参数应该被明确指定为 void
。
然而,直接使用 std::future<void>
可能并不常见,因为 std::future
的主要用途是检索异步任务的结果。当任务没有返回值时,你更可能只是关心任务是否完成,而不是它的结果。对于这种情况,std::future<void>
仍然可以工作,但你可能更想使用 std::promise<void>
和 std::shared_future<void>
来与异步任务进行交互。
以下是一个使用 std::promise<void>
和 std::future<void>
的简单示例:
#include <iostream>
#include <thread>
#include <future>
void async_task(std::promise<void> prom) {
// 模拟一些异步工作
std::this_thread::sleep_for(std::chrono::seconds(2));
// 当工作完成时,设置 promise 的值(对于 void 类型,我们调用 set_value() 但不传递任何参数)
prom.set_value();
}
int main() {
// 创建一个 promise 对象
std::promise<void> prom;
// 从 promise 对象中获取 future 对象
std::future<void> fut = prom.get_future();
// 在新线程中运行异步任务
std::thread t(async_task, std::move(prom));
// 在主线程中等待异步任务完成
fut.wait(); // 对于 void 类型的 future,我们只需要等待它完成,而不是检索结果
std::cout << "Async task completed.\n";
// 确保线程完成后再退出 main 函数
t.join();
return 0;
}
在这个示例中,我们创建了一个 std::promise<void>
对象,并从中获取了一个 std::future<void>
对象。然后,我们在一个新线程中运行异步任务,并在主线程中等待该任务完成。由于异步任务不返回任何值,因此我们只关心 std::future<void>
的 wait()
方法来确保任务已经完成。
3 std::promise
提供一个不同线程间的数据同步机制,可以存储一个某种类型的值,并将其传递给对应的future,即使这个future和promise不再同一个线程中也可以安全访问该值。
通过get_future来获取与该promise对象相关联的future对象,调用该函数之后,两个对象共享相同的shared state。
set_value()用于设置共享状态的值,将promise的共享状态标志变为ready。
promise对象是异步Provider,可在某一时刻设置共享状态的值
future对象可以异步返回共享状态的值,或者在必要的情况下阻塞调用者并等待共享状态变为ready,然后获取共享状态的值。
4 std::future & std::promise example
#include <iostream>
#include <thread>
#include <future>
void func(int x, int y, std::promise<int> &promiseObj) {
promiseObj.set_value(x + y);
}
void test() {
int a{10};
int b{8};
std::promise<int> promiseObj;
std::future<int> futureObj = promiseObj.get_future();
std::thread t(func, a, b, std::ref(promiseObj));
t.join();
int sum = futureObj.get();
std::cout << "sum= " << sum << std::endl;
return 0;
}
5 std::shared_future
std::shared_future
是 C++11 引入的一个类,用于从多个线程中共享对某个异步任务的结果的访问。std::shared_future
与 std::future
类似,但有一个重要的区别:std::shared_future
的实例可以被复制并传递给多个线程,而 std::future
的实例在被移动后就不能再被访问了。
当你有一个 std::promise
对象,并且你想让多个线程能够访问其关联的 std::future
对象以获取异步任务的结果时,std::shared_future
就变得非常有用。但是,你不能直接从 std::promise
获取 std::shared_future
;你需要首先获取一个 std::future
,然后使用 std::future::share
方法来创建 std::shared_future
。但在实际使用中,通常通过 std::async
或其他异步操作直接获取 std::shared_future
。
以下是一个简单的示例,展示了如何使用 std::async
和 std::shared_future
:
#include <iostream>
#include <future>
#include <thread>
int compute_something(int x) {
// 假设这是一个耗时的计算
return x * x;
}
int main() {
// 使用 std::async 启动一个异步任务,并获取 std::shared_future
std::shared_future<int> result = std::async(std::launch::async, compute_something, 42);
// 在主线程中做一些其他事情
// ...
// 等待异步任务完成并获取结果
int value = result.get();
std::cout << "The result is " << value << std::endl;
return 0;
}
注意,虽然在这个例子中我们只在一个线程中使用了 std::shared_future
,但你可以将其复制到多个线程中,并在所有线程上调用 get()
。只要一个线程调用了 get()
,shared_future
的状态就会变为 ready
,其他所有线程再调用 get()
时都会立即返回结果,而不需要等待异步任务完成。但是,如果异步任务还没有完成,并且没有线程调用 get()
,那么第一个调用 get()
的线程将会阻塞,直到异步任务完成。
还要注意,尽管 std::shared_future
允许多个线程访问异步任务的结果,但它并不提供对结果的同步访问。如果你需要多个线程同时读写某个共享数据,你应该使用其他的同步机制(如互斥锁)来确保数据的一致性。
N 参考资料
https://www.cnblogs.com/linuxAndMcu/p/14577275.html