async用法
std::async
是一个用于异步执行函数的模板函数,它返回一个 std::future
对象,该对象用于获取函数的返回值。
#include<iostream>
#include<future>
#include<chrono>
std::string fetchDataFromDB(std::string query) {
std::this_thread::sleep_for(std::chrono::seconds(5));
return "Data: " + query;
}
int main() {
std::future<std::string> resultFromDB = std::async(std::launch::async, fetchDataFromDB, "myData");
//在主线程中做其他的事情
std::cout << "Doing something else ..." << std::endl;
//从future对象中获取数据
std::string dbData = resultFromDB.get();
std::cout << dbData << std::endl;
return 0;
}
在这个示例中,std::async
创建了一个新的线程(或从内部线程池中挑选一个线程)并自动与一个 std::promise
对象相关联。std::promise
对象被传递给 fetchDataFromDB 函数,函数的返回值被存储在 std::future
对象中。在主线程中,我们可以使用 std::future::get
方法从 std::future
对象中获取数据。注意,在使用 std::async
的情况下,我们必须使用 std::launch::async
标志来明确表明我们希望函数异步执行。
async的启动策略
std::async
函数可以接受几个不同的启动策略,这些策略在std::launch
枚举中定义。除了std::launch::async
之外,还有以下启动策略:
std::launch::deferred
:这种策略意味着任务将在调用std::future::get()或std::future::wait()函数时延迟执行。换句话说,任务将在需要结果时同步执行。
std::launch::async | std::launch::deferred
:这种策略是上面两个策略的组合。任务可以在一个单独的线程上异步执行,也可以延迟执行,具体取决于实现。
future的wait和get
std::future::get()
和 std::future::wait()
是 C++ 中用于处理异步任务的两个方法,它们的功能和用法有一些重要的区别。
std::future::get()
:
std::future::get() 是一个阻塞调用,用于获取 std::future 对象表示的值或异常。如果异步任务还没有完成,get() 会阻塞当前线程,直到任务完成。如果任务已经完成,get() 会立即返回任务的结果。重要的是,get() 只能调用一次,因为它会移动或消耗掉 std::future 对象的状态。一旦 get() 被调用,std::future 对象就不能再被用来获取结果。
std::future::wait()
:
std::future::wait() 也是一个阻塞调用,但它与 get() 的主要区别在于 wait() 不会返回任务的结果。它只是等待异步任务完成。如果任务已经完成,wait() 会立即返回。如果任务还没有完成,wait() 会阻塞当前线程,直到任务完成。与 get() 不同,wait() 可以被多次调用,它不会消耗掉 std::future 对象的状态。
总结
- std::future::get() 用于获取并返回任务的结果,而 std::future::wait() 只是等待任务完成。
- get() 只能调用一次,而 wait() 可以被多次调用。
- 如果任务还没有完成,get() 和 wait() 都会阻塞当前线程,但 get() 会一直阻塞直到任务完成并返回结果,而 wait() 只是在等待任务完成。
你可以使用std::future的wait_for()或wait_until()方法来检查异步操作是否已完成。这些方法返回一个表示操作状态的std::future_status值。
if(fut.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
// 操作已完成
} else {
// 操作尚未完成
}
将任务和future关联
std::packaged_task
和std::future
是C++11中引入的两个类,它们用于处理异步任务的结果。
std::packaged_task
是一个可调用目标,它包装了一个任务,该任务可以在另一个线程上运行。它可以捕获任务的返回值或异常,并将其存储在std::future
对象中,以便以后使用。
std::future
代表一个异步操作的结果。它可以用于从异步任务中获取返回值或异常。
以下是使用std::packaged_task
和std::future
的基本步骤:
1、创建一个std::packaged_task
对象,该对象包装了要执行的任务。
2、调用std::packaged_task
对象的get_future()
方法,该方法返回一个与任务关联的std::future
对象。
3、在另一个线程上调用std::packaged_task
对象的operator()
,以执行任务。
4、在需要任务结果的地方,调用与任务关联的std::future
对象的get()
方法,以获取任务的返回值或异常。
int myTask() {
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "my task run 5 s" << std::endl;
return 42;
}
void use_package() {
// 创建一个包装了任务的 std::packaged_task 对象
std::packaged_task<int()> task(myTask);
// 获取与任务关联的 std::future 对象
std::future<int> result = task.get_future();
// 在另一个线程上执行任务
std::thread t(std::move(task));
t.detach();
//等待任务完成获取结果
int value = result.get();
std::cout << "The result is: " << value << std::endl;
}
int main() {
use_package();
}
在上面的示例中,我们创建了一个包装了任务的std::packaged_task对象,并获取了与任务关联的std::future对象。然后,我们在另一个线程上执行任务,并等待任务完成并获取结果。最后,我们输出结果。
我们可以使用 std::function 和 std::package_task 来包装带参数的函数。std::package_task 是一个模板类,它包装了一个可调用对象,并允许我们将其作为异步任务传递。
promise 用法
C++11引入了std::promise
和std::future
两个类,用于实现异步编程。std::promise
用于在某一线程中设置某个值或异常,而std::future
则用于在另一线程中获取这个值或异常。
void setValue(std::promise<int> prom) {
prom.set_value(10);
}
int main() {
// 创建一个 promise 对象
std::promise<int> prom;
//获取与 promise 相关联的 future 对象
std::future<int> fut = prom.get_future();
//在新线程中设置 promise 的值
std::thread t(setValue, std::move(prom));
// 在主线程中获取 future 的值
std::cout << "Waiting for the thread to set the value...\n";
std::cout << "Value set by the thread: " << fut.get() << '\n';
t.join();
return 0;
}
在上面的代码中,
首先创建了一个std::promise<int>
对象,然后通过调用get_future()
方法获取与之相关联的std::future<int>
对象。然后,我们在新线程中通过调用set_value()
方法设置promise
的值,并在主线程中通过调用fut.get()
方法获取这个值。注意,在调用fut.get()
方法时,如果promise
的值还没有被设置,则该方法会阻塞当前线程,直到值被设置为止。
共享类型future
当我们需要多个线程等待同一个执行结果时,需要使用std::shared_future
假设你有一个异步任务,需要多个线程等待其完成,然后这些线程需要访问任务的结果。在这种情况下,你可以使用std::shared_future来共享异步任务的结果。
void myFunction(std::promise<int>&& promise) {
// 模拟一些工作
std::this_thread::sleep_for(std::chrono::seconds(1));
promise.set_value(42); // 设置 promise 的值
}
void threadFunction(std::shared_future<int> future) {
try {
int result = future.get();
std::cout << "Result: " << result << std::endl;
}
catch (const std::future_error& e) {
std::cout << "Future error: " << e.what() << std::endl;
}
}
void use_shared_future() {
std::promise<int> promise;
std::shared_future<int> future = promise.get_future();
std::thread myThread1(myFunction, std::move(promise)); // 将 promise 移动到线程中
// 使用 share() 方法获取新的 shared_future 对象
std::thread myThread2(threadFunction, future);
std::thread myThread3(threadFunction, future);
myThread1.join();
myThread2.join();
myThread3.join();
}
在这个示例中,我们创建了一个std::promise<int>
对象promise和一个与之关联的std::shared_future<int>
对象future。然后,我们将promise对象移动到另一个线程myThread1中,该线程将执行myFunction函数,并在完成后设置promise的值。我们还创建了两个线程myThread2和myThread3,它们将等待future对象的结果。如果myThread1成功地设置了promise的值,那么future.get()将返回该值。这些线程可以同时访问和等待future对象的结果,而不会相互干扰。
参考自:恋恋风辰的官方博客