在C++中,"promise"是一个表示尚未可用但将在未来某个时间点提供的值的对象。它是并发支持库的一部分,通常与future和async任务一起使用,用于处理异步编程并在不同线程或任务之间进行通信。
promise的概念与"Future-Promise"设计模式相关,该模式允许一个线程(或任务)生成一个值,并在值就绪后将其提供给另一个线程(或任务)进行使用。
以下是promise的基本工作原理:
1. 创建Promise:创建一个promise对象来保存以后将生成的值。
2. 值的履行:promise的持有者(生产者)使用`set_value()`方法设置promise的值。一旦值被设置,promise就变为就绪状态。
3. 获取Future:将future对象与promise关联,其他代码的部分(消费者)可以使用此future在值就绪后检索值。future可以用于等待promise的履行并通过`get()`方法获取结果。
4. 异步执行:promise通常与`std::async`或`std::promise::async`结合使用,以异步方式执行任务,并稍后检索其结果。
以下是一个简单的例子:
#include <iostream>
#include <future>
int main() {
// 创建一个promise并获取其关联的future
std::promise<int> promiseObj;
std::future<int> futureObj = promiseObj.get_future();
// 使用lambda函数启动一个异步任务
std::thread([](std::promise<int>& promise) {
// 模拟一些工作
std::this_thread::sleep_for(std::chrono::seconds(2));
// 设置promise的值
int result = 42;
promise.set_value(result);
}, std::ref(promiseObj)).detach();
// 等待future就绪并检索结果
int result = futureObj.get();
// 打印结果
std::cout << "Result: " << result << std::endl;
return 0;
}
在这个例子中,我们创建一个promise来保存一个`int`类型的值。然后,我们使用lambda函数启动一个异步任务,该任务将在模拟的延迟后设置promise的值。主线程等待future就绪并使用`get()`检索结果,在值可用时打印结果。
Promise和Future对于管理异步操作、多线程和并行编程在C++中非常有用。它们允许不同部分的程序在并发运行时进行简单的通信和同步。
以下是包含了 `std::promise`、`std::future` 和 `std::async` 的示例:
#include <iostream>
#include <future>
// Function that performs a computation and returns a value asynchronously
int computeSum(int a, int b) {
std::this_thread::sleep_for(std::chrono::seconds(2));
return a + b;
}
int main() {
// Using std::async to execute the computeSum function asynchronously
std::future<int> futureResult = std::async(std::launch::async, computeSum, 10, 20);
// Do some other work while the computation is being performed...
// Retrieve the result from the future when it's ready
int result = futureResult.get();
std::cout << "Sum: " << result << std::endl;
return 0;
}
在这个例子中:
1. 定义了 `计算求和` 函数,它执行一个计算(通过休眠2秒来模拟)并返回两个整数 `a` 和 `b` 的和。
2. 在 `main()` 函数中,使用 `std::async` 异步启动 `计算求和` 函数。`std::async` 的第一个参数指定启动策略,这里设置为 `std::launch::async`,表示在单独的线程中运行该函数。后续参数传递给 `计算求和` 函数(在这里是 10 和 20)。
3. 在计算执行异步运算的同时,主线程可以执行其他工作。
4. 使用 `get()` 从 `未来结果` 对象中获取计算结果。如果结果还没有准备好,`get()` 调用会阻塞,直到计算完成并返回结果。
5. 最后,将计算的和打印到控制台。
另外,您还可以使用 `std::promise` 来实现类似的功能:
#include <iostream>
#include <future>
int main() {
// Create a promise and get its associated future
std::promise<int> promiseObj;
std::future<int> futureObj = promiseObj.get_future();
// Start an asynchronous task using a lambda function
std::thread([](std::promise<int>& promise) {
// Simulate some work
std::this_thread::sleep_for(std::chrono::seconds(2));
// Set the value of the promise
int result = 42;
promise.set_value(result);
}, std::ref(promiseObj)).detach();
// Wait for the future to be ready and retrieve the result
int result = futureObj.get();
// Print the result
std::cout << "Result: " << result << std::endl;
return 0;
}
在这个例子中,我们定义了 `计算求和` 函数来接受一个 `std::promise` 的引用,并使用 `set_value()` 来设置计算结果。其余的代码与之前的示例类似,但我们明确使用了 `std::promise` 来设置计算的结果。
这两个示例都实现了异步执行一个函数并使用 `std::async` 或 `std::promise` 结合 `std::future` 来获取其结果。选择使用 `std::async` 还是 `std::promise` 取决于具体的用例和应用程序的设计需求。
如果在关联的 `std::future` 对象的未来结果还没有准备好(即异步任务尚未完成),当调用 `get()` 方法时,调用线程将会被阻塞,并等待结果变为可用。换句话说,`get()` 方法会等待直到未来结果就绪,并且在就绪后返回结果。
然而,如果由于异常或其他原因无法检索未来结果,调用 `get()` 可能会抛出异常。具体来说,如果未来结果无效(例如,它没有与 promise 或任务关联),或者与未来关联的共享状态已被放弃或销毁,那么将会抛出 `std::future_error` 异常,附带适当的错误代码。
为了处理潜在的异常并避免无限期地阻塞,最佳实践是将对 `get()` 的调用放在 try-catch 块中。这样,您可以处理在检索未来结果期间可能抛出的任何异常。
以下是演示行为的示例:
#include <iostream>
#include <future>
int main() {
std::future<int> futureResult = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::seconds(5));
return 42;
});
// 在未等待未来就绪的情况下调用 get()
try {
int result = futureResult.get();
std::cout << "结果: " << result << std::endl;
} catch (const std::exception& ex) {
std::cout << "发生异常: " << ex.what() << std::endl;
}
return 0;
}
在这个例子中,`std::async` 函数用于启动一个异步任务,它将休眠5秒,然后返回值 42。然而,我们立即调用 `get()` 而不等待任务完成。结果是,`get()` 调用将会阻塞5秒,直到未来就绪,然后打印结果。如果在 `get()` 调用期间发生异常,它将在 `catch` 块中被捕获,并显示错误消息。