2011-09-25 45 views
7

Sau this excellent tutorial cho tương lai, lời hứanhiệm vụ đóng gói tôi đã đến điểm mà tôi muốn chuẩn bị nhiệm vụ của riêng tôiLàm cách nào để tạo gói packaged_task với các tham số?

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

Theo như tôi có thể giải mã gcc-4.7.0 thông báo lỗi nó mong đợi các đối số khác nhau? Nhưng bằng cách nào? Tôi cố gắng để rút ngắn được thông báo lỗi:

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' 

là biến thể của tôi như thế nào tôi cung cấp các tham số cho ackermann sai? Hoặc thông số mẫu không đúng? Tôi không đưa ra các tham số 3,11 để tạo chủ đề, đúng không?

Cập nhật biến không thành công khác:

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 ... là nó với tôi, hoặc là nó beta-gcc?

Trả lời

16

Thứ nhất, nếu bạn khai báo std::packaged_task để lấy đối số, thì bạn phải chuyển chúng đến operator(), chứ không phải hàm tạo. Trong một chủ đề duy nhất bạn do đó có thể làm:

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

Để thực hiện điều tương tự với một chủ đề, bạn phải di chuyển nhiệm vụ vào các chủ đề, và vượt qua các đối số quá:

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; 

Ngoài ra, bạn có thể ràng buộc các đối số trực tiếp trước khi bạn xây dựng nhiệm vụ, trong trường hợp đó, nhiệm vụ chính nó bây giờ có chữ ký mà không có đối số:

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

Aga nhập, bạn có thể làm điều này và vượt qua nó 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; 

Tất cả những ví dụ nên làm việc (và làm, với cả hai g ++ 4.6 và MSVC2010 và just::thread thực hiện của tôi về thư viện thread). Nếu có thì không có lỗi trong trình biên dịch hoặc thư viện bạn đang sử dụng. Ví dụ: thư viện được chuyển với g ++ 4.6 không thể xử lý các đối tượng di chuyển ngang như std::packaged_task đến std::thread (và do đó không xử lý được các ví dụ thứ 2 và thứ 4), vì nó sử dụng std::bind làm chi tiết triển khai và việc thực thi std::bind không chính xác.

+3

Xem xét các yêu cầu đối với 'std :: bind', không đúng là các đối số được yêu cầu phải có thể sao chép được. Đoạn văn quá dài để dán ở đây, nó là 20.8.9.1.2 Mẫu chức năng liên kết [func.bind.bind] đoạn 5. Các yêu cầu thực tế là các kiểu được lưu trữ được di chuyển có thể xây dựng và có thể xây dựng được từ các đối số đã truyền. Mặc dù tôi nhớ một vận chuyển thực hiện bị lỗi với GCC đã yêu cầu CopyConstructible. (Tuy nhiên, không phải vấn đề mà OP phải đối mặt.) –

+0

@Luc: bạn nói đúng, tôi đã sai. –

+0

Mã hoạt động, nhưng tôi có một câu hỏi trong dòng 'std :: unique_lock l (td.m);' không phải là mutex trong chuỗi đã bị khóa khi nó đang kiểm tra biến điều kiện? Tôi nghĩ rằng tôi đang thiếu một cái gì đó ở đó. Tôi nghĩ rằng nó khóa mutex trong thread và sau đó chờ cho lá cờ dừng hoặc cho công việc được thêm vào hàng đợi. Trong trường hợp này sẽ không phải là chủ đề chính tiếp tục chờ đợi cho khóa để phát hành? Đây có phải là vì một sự thức tỉnh giả mạo rằng điều này hoạt động? – bjackfly

3

Vì bạn đang bắt đầu chuỗi không có đối số, bạn mong đợi nhiệm vụ được bắt đầu mà không có đối số, như thể task1() đã được sử dụng. Do đó chữ ký mà bạn muốn hỗ trợ không phải là int(int, int) nhưng int(). Đổi lại, điều này có nghĩa rằng bạn phải vượt qua một hàm functor tương thích với chữ ký này cho hàm tạo của std::packaged_task<int()>. Hãy thử:

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

Một khả năng khác là:

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

vì các nhà xây dựng của std::thread có thể chấp nhận đối số. Ở đây, các functor bạn vượt qua nó sẽ được sử dụng như thể task1(3, 11) đã được sử dụng.

+0

Than ôi, không. Có lẽ tôi thử một functor cho 'ackermann' – towi

+0

@towi 'Không' với cái gì? Một lỗi biên dịch một lần nữa? Lỗi là gì? –

+0

Có, các lỗi khác nhau. Tôi nghĩ rằng gần nhất tôi có (danh sách lỗi ngắn nhất) là: 'packaged_task task1 (bind (ack, 3,11)); thread th1 {move (task1)}; 'với lỗi:' tuple: 274: 17: error: 'constexpr std :: _ Tuple_impl <### = std :: _ Tuple_impl <0ul, std :: packaged_task >]' khai báo thành lấy tham chiếu const, nhưng khai báo ngầm sẽ lấy không const' – towi

Các vấn đề liên quan