如何创建带有参数的packaged_task?

发布于 2024-12-06 13:37:11 字数 1710 浏览 0 评论 0原文

遵循这个关于期货的优秀教程 /em>、承诺打包任务我已经到了想要准备自己的任务的程度,

#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();
}

据我所知, gcc-4.7.0 错误消息它期望参数不同吗?但如何呢?我尝试缩短错误消息:

error: no matching function for call to 
  'std::packaged_task<int(int, int)>::packaged_task(<brace-enclosed initializer list>)'
note: candidates are:
  std::packaged_task<_Res(_ArgTypes ...)>::---<_Res(_ArgTypes ...)>&&) ---
note:   candidate expects 1 argument, 3 provided
  ...
note:   cannot convert 'ackermann'
  (type 'int (*)(int, int)') to type 'std::allocator_arg_t'

我为ackermann提供参数的变体是否错误?或者是错误的模板参数?我没有给线程的创建参数3,11,对吧?

更新其他不成功的变体:

packaged_task<int()> task1 ( []{return ackermann(3,11);} );
thread th1 { move(task1)  };

packaged_task<int()> task1 ( bind(&ackermann,3,11) );
thread th1 { move(task1)  };

packaged_task<int(int,int)> task1 ( &ackermann );
thread th1 { move(task1), 3,11  };

嗯...是我,还是beta-gcc?

Following this excellent tutorial for futures, promises and packaged tasks I got to the the point where I wanted to prepare my own task

#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();
}

As far as I can decipher the gcc-4.7.0 error message it expects the arguments differently? But how? I try to shorten the error message:

error: no matching function for call to 
  'std::packaged_task<int(int, int)>::packaged_task(<brace-enclosed initializer list>)'
note: candidates are:
  std::packaged_task<_Res(_ArgTypes ...)>::---<_Res(_ArgTypes ...)>&&) ---
note:   candidate expects 1 argument, 3 provided
  ...
note:   cannot convert 'ackermann'
  (type 'int (*)(int, int)') to type 'std::allocator_arg_t'

Is my variant how I provide the parameters for ackermann wrong? Or is it the wrong template parameter? I do not give the parameters 3,11 to the creation of thread, right?

Update other unsuccessful variants:

packaged_task<int()> task1 ( []{return ackermann(3,11);} );
thread th1 { move(task1)  };

packaged_task<int()> task1 ( bind(&ackermann,3,11) );
thread th1 { move(task1)  };

packaged_task<int(int,int)> task1 ( &ackermann );
thread th1 { move(task1), 3,11  };

hmm... is it me, or is it the beta-gcc?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

许久 2024-12-13 13:37:11

首先,如果您声明 std::packaged_task 来接受参数,那么您必须将它们传递给 operator(),而不是构造函数。在单个线程中,您可以这样做:

std::packaged_task<int(int,int)> task(&ackermann);
auto f=task.get_future();
task(3,11);
std::cout<<f.get()<<std::endl;

要对线程执行相同的操作,您必须将任务移动到线程中,并传递参数:

std::packaged_task<int(int,int)> task(&ackermann);
auto f=task.get_future();
std::thread t(std::move(task),3,11);
t.join();
std::cout<<f.get()<<std::endl;

或者,您可以在构造之前直接绑定参数任务,在这种情况下,任务本身现在有一个不带参数的签名:

std::packaged_task<int()> task(std::bind(&ackermann,3,11));
auto f=task.get_future();
task();
std::cout<<f.get()<<std::endl;

同样,您可以执行此操作并将其传递给线程:

std::packaged_task<int()> task(std::bind(&ackermann,3,11));
auto f=task.get_future();
std::thread t(std::move(task));
t.join();
std::cout<<f.get()<<std::endl;

所有这些示例都应该有效(并且对于 g++ 4.6 和 MSVC2010 以及我的 <一个href="http://www.stdthread.co.uk" rel="noreferrer">只是::thread 线程库的实现)。如果没有,那么您正在使用的编译器或库中存在错误。例如,g++ 4.6 附带的库无法处理将仅移动对象(例如 std::packaged_task)传递到 std::thread(因此无法处理第二个和第四个示例),因为它使用 std::bind 作为实现细节,并且 std::bind 的实现错误地要求参数是可复制的。

Firstly, if you declare std::packaged_task to take arguments, then you must pass them to operator(), not the constructor. In a single thread you can thus do:

std::packaged_task<int(int,int)> task(&ackermann);
auto f=task.get_future();
task(3,11);
std::cout<<f.get()<<std::endl;

To do the same with a thread, you must move the task into the thread, and pass the arguments too:

std::packaged_task<int(int,int)> task(&ackermann);
auto f=task.get_future();
std::thread t(std::move(task),3,11);
t.join();
std::cout<<f.get()<<std::endl;

Alternatively, you can bind the arguments directly before you construct the task, in which case the task itself now has a signature that takes no arguments:

std::packaged_task<int()> task(std::bind(&ackermann,3,11));
auto f=task.get_future();
task();
std::cout<<f.get()<<std::endl;

Again, you can do this and pass it to a thread:

std::packaged_task<int()> task(std::bind(&ackermann,3,11));
auto f=task.get_future();
std::thread t(std::move(task));
t.join();
std::cout<<f.get()<<std::endl;

All of these examples should work (and do, with both g++ 4.6 and MSVC2010 and my just::thread implementation of the thread library). If any do not then there is a bug in the compiler or library you are using. For example, the library shipped with g++ 4.6 cannot handle passing move-only objects such as a std::packaged_task to std::thread (and thus fails to handle the 2nd and 4th examples), since it uses std::bind as an implementation detail, and that implementation of std::bind incorrectly requires that the arguments are copyable.

风吹雨成花 2024-12-13 13:37:11

由于您在不带参数的情况下启动线程,因此您希望任务在不带参数的情况下启动,就像使用 task1() 一样。因此,您想要支持的签名不是 int(int, int) 而是 int()。反过来,这意味着您必须将与此签名兼容的函子传递给 std::packaged_task 的构造函数。尝试:

packaged_task<int()> task1 { std::bind(&ackermann, 3, 11) };

另一种可能是:

packaged_task<int(int,int)> task1 { &ackermann };
auto f1 = task1.get_future();
thread th1 { move(task1), 3, 11 };

因为std::thread的构造函数可以接受参数。在这里,您传递给它的函子将像使用 task1(3, 11) 一样使用。

Since you're starting the thread with no arguments, you expect the task to be started with no arguments, as if task1() were used. Hence the signature that you want to support is not int(int, int) but int(). In turn, this means that you must pass a functor that is compatible with this signature to the constructor of std::packaged_task<int()>. Try:

packaged_task<int()> task1 { std::bind(&ackermann, 3, 11) };

Another possibility is:

packaged_task<int(int,int)> task1 { &ackermann };
auto f1 = task1.get_future();
thread th1 { move(task1), 3, 11 };

because the constructor of std::thread can accept arguments. Here, the functor you pass to it will be used as if task1(3, 11) were used.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文