在使用C++ 11的线程模型时,我注意到了这一点
std::packaged_task<int(int,int)> task([](int a, int b) { return a + b; });
auto f = task.get_future();
task(2,3);
std::cout << f.get() << '\n';
Run Code Online (Sandbox Code Playgroud)
和
auto f = std::async(std::launch::async,
[](int a, int b) { return a + b; }, 2, 3);
std::cout << f.get() << '\n';
Run Code Online (Sandbox Code Playgroud)
似乎做了完全相同的事情.据我所知,有可能是一个重大的区别,如果我跑std::async带std::launch::deferred,但有一个在这种情况下?
这两种方法有什么区别,更重要的是,我应该使用哪种用例?
我应该什么时候使用std::promise过std::async或std::packaged_task?你能告诉我何时使用它们的实际例子吗?
在使用打包任务时,我遇到了一些非常奇怪的事情.当读取~packched_task时,我得到的印象是,如果a std::packaged_task在执行之前被销毁,那么承诺将被破坏并且尝试从未来获得结果应该抛出std::future_error.
但是,在Visual Studio 2013上,情况似乎并非如此.请使用以下代码:
#include <iostream>
#include <future>
#include <functional>
int main() {
std::future<int> f;
{
std::packaged_task<int()> task([](){return 3; });
f = task.get_future();
}
std::cout<<f.get()<<std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我期待得到一个std::future_error开启,f.get()但它阻止,等待打包的任务被执行.
尝试另一个编译器:http://ideone.com/Wt0WOc确实扔了std::future_error("Broken promise")...
我是否在Visual Studio 2013中看到了一个错误或者我错过了什么?
似乎除非你打电话给std::async一个std::future遗嘱永远不会被设置为任何其他状态,future_status::deferred除非你打电话get或wait未来.即使任务已经运行并存储结果wait_for,它wait_until也将继续不阻止和返回future_status::deferred.
这是一个例子:
#include <future>
void main()
{
auto func = []() { return 5; };
auto asyncFuture = std::async(std::launch::async, func);
auto status = asyncFuture.wait_for(std::chrono::seconds(0)); // timeout (1)
auto deferredFuture = std::async(std::launch::deferred, func);
status = deferredFuture.wait_for(std::chrono::seconds(0)); // deferred (2)
std::packaged_task<int()> task(func);
auto packagedTaskFuture = task.get_future();
status = packagedTaskFuture.wait_for(std::chrono::seconds(0)); // deferred (2)
task();
status = packagedTaskFuture.wait_for(std::chrono::seconds(0)); // deferred (2)
packagedTaskFuture.wait();
status = packagedTaskFuture.wait_for(std::chrono::seconds(0)); // ready (0) …Run Code Online (Sandbox Code Playgroud) 在这个关于期货,承诺和打包任务的优秀教程之后,我达到了我想要准备自己的任务的地步
#include <iostream>
#include <future>
using namespace std;
int ackermann(int m, int n) { // might take a while
if(m==0) return n+1;
if(n==0) return ackermann(m-1,1);
return ackermann(m-1, ackermann(m, n-1));
}
int main () {
packaged_task<int(int,int)> task1 { &ackermann, 3, 11 }; // <- error
auto f1 = task1.get_future();
thread th1 { move(task1) }; // call
cout << " ack(3,11):" << f1.get() << endl;
th1.join();
}
Run Code Online (Sandbox Code Playgroud)
至于我可以解密gcc-4.7.0错误消息,它期望参数不同吗?但是怎么样?我尝试缩短错误消息:
error: no matching function for …Run Code Online (Sandbox Code Playgroud) 我最近运行valgrind --tool=helgrind了我的项目并收到了一条警告"可能的数据竞争",我认为这是一个问题.但是,即使是这个简单的测试程序也会导致以下消息:
#include <iostream>
#include <thread>
#include <future>
int main()
{
std::packaged_task<void()> task([]()
{
std::cout << "Hello\n"; // You can leave this out
});
auto future = task.get_future();
std::thread(std::move(task)).detach();
future.get();
}
Run Code Online (Sandbox Code Playgroud)
编译g++-4.9 -p -g -std=c++11 -pthread -O3 test.cpp,输出valgrind --tool=helgrind ./a.out是:
==12808== Helgrind, a thread error detector
==12808== Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.
==12808== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==12808== Command: ./a.out
==12808==
Hello …Run Code Online (Sandbox Code Playgroud) std::future从 a创建 a 是否安全std::packaged_task,该 a 在单独的线程上执行,但并不总是检索其结果?
#include <future>
#include <thread>
class Result {
Result() {}
~Result() {}
};
void foo() {
std::packaged_task<Result()> task(..);
auto future = task.get_future();
std::thread thread(std::move(task), ...);
thread.detach();
if (future.wait_for(std::chrono::milliseconds(timeout_ms)) == std::future_status::ready) {
auto result = future.get(); <--- Task didn't take too long, retrieve future result
...
}
} <--- Task is taking too long, just abort and never call future.get()
Run Code Online (Sandbox Code Playgroud)
它似乎适用于 Clang / libc++: ~Result()is Called on the returned result by the …
我知道了future返回的原因std::async有一些特殊的共享状态,通过它wait on returned future发生在未来的析构函数中。但是当我们使用 时std::pakaged_task,它的未来不会表现出相同的行为。为了完成任务打包,你必须显式调用get()上future的对象packaged_task。
现在我的问题是:
std::async与std::packaged_task)的内部实现可能是什么?futurereturn from std::packaged_task?或者,换句话说,相同的行为是如何停止的std::packaged_task future?要查看上下文,请查看以下代码:
它不会等待完成countdown任务。但是,如果我取消评论// int value = ret.get();,它就会结束countdown并且很明显,因为我们实际上是在阻止返回的未来。
// packaged_task example
#include <iostream> // std::cout
#include <future> // std::packaged_task, std::future
#include <chrono> // std::chrono::seconds
#include <thread> // std::thread, std::this_thread::sleep_for
// count down taking a second for each value:
int countdown (int from, …Run Code Online (Sandbox Code Playgroud) 使用MSVC2012,
以下代码将按预期编译和运行
std::packaged_task< int() > task( []()->int{ std::cout << "hello world" << std::endl; return 0; } );
std::thread t( std::move(task) );
t.join();
Run Code Online (Sandbox Code Playgroud)
而以下代码将无法编译和运行
std::packaged_task< void() > task( [](){ std::cout << "hello world" << std::endl; } );
std::thread t( std::move(task) );
t.join();
Run Code Online (Sandbox Code Playgroud)
为什么会这样?
编辑:作为一种解决方法,可以使用std :: promise在返回void的函数上获取std :: future
std::promise<void> promise;
auto future = promise.get_future();
std::thread thread( [](std::promise<void> &p){ std::cout << "hello world" << std::endl; p.set_value(); }, std::move(promise) );
future.wait();
Run Code Online (Sandbox Code Playgroud)
请注意,带有std :: thread的vs2012库中存在一个错误,它会强制您将promise作为l值引用传递并移动promise,如果按值传递promise或r-则不会编译价值参考.这应该是因为实现使用std :: bind(),它的行为不符合预期.
我的假设是packaged_task有一个promise底层.如果我的任务抛出异常,我该如何将其路由到关联的future?只有一个promise我可以打电话set_exception
- 我该如何做同样的事情packaged_task?
packaged-task ×10
c++ ×9
c++11 ×7
future ×5
promise ×2
stdasync ×2
asynchronous ×1
c++14 ×1
pthreads ×1
std-future ×1
stdthread ×1
valgrind ×1