2015-05-29 17 views
5

Tôi đã viết mã sau để kiểm tra std::async() về các chức năng trả về void với GCC 4.8.2 trên Ubuntu.Là std :: async đảm bảo được gọi cho các hàm trả về void?

#include <future> 
#include <iostream> 

void functionTBC() 
{ 
    std::cerr << "Print here\n"; 
} 

int main(void) 
{ 
#ifdef USE_ASYNC 
    auto i = std::async(std::launch::async, functionTBC); 
#else 
    auto i = std::async(std::launch::deferred, functionTBC); 
#endif 
    //i.get(); 
    return 0; 
} 

Nếu i.get(); không được chú ý, thông báo "Print here" luôn tồn tại; tuy nhiên, nếu i.get(); được nhận xét, "Print here" sẽ tồn tại nếu và chỉ khi USE_ASYNC được xác định (nghĩa là, std::launch::async luôn dẫn đến thông báo được in ra trong khi std::launch::deferred không bao giờ).

Hành vi được đảm bảo này? Cách chính xác để đảm bảo cuộc gọi không đồng bộ trở về void sẽ được thực thi là gì?

+4

Nếu bạn yêu cầu khởi chạy hoãn lại và không bao giờ gọi. Hãy quên đi tương lai đó, chức năng của bạn sẽ không bao giờ được thực hiện. Điều này không liên quan gì đến hàm trả về void hoặc bất kỳ kiểu nào khác. – sbabbi

Trả lời

7

std::launch::deferred có nghĩa là "không chạy điều này cho đến khi tôi .wait() hoặc .get()".

Vì bạn chưa bao giờ .get() hoặc .wait() ed, nó không bao giờ chạy.

void không liên quan gì đến điều này.

Đối với std::launch::async, tiêu chuẩn cho biết rằng hàm hủy của tương lai đã trả về (~future) sẽ chặn cho đến khi tác vụ hoàn tất (nghĩa là có một ẩn số .wait()). Điều này bị vi phạm bởi MSVC, vì họ không đồng ý với quyết định thiết kế đó, và họ đang chiến đấu để thay đổi tiêu chuẩn: trong thực tế, điều này có nghĩa là bạn không thể dựa vào bất kỳ hành vi nào từ std::launch::async trả lại future nếu bạn muốn tương lai ma cua ban.

Nếu không có ẩn ý wait trong ~future, sẽ không xác định nếu thực sự đã gọi hàm khi thoát main. Nó có thể đã xảy ra hay không. Có thể bạn có thể gọi UB bằng cách có chủ đề vẫn hoạt động ở cuối main.

Bạn có thể thắc mắc sử dụng deferred có: bạn có thể sử dụng nó để xếp hàng tính toán để đánh giá lười biếng.

+0

Nếu tôi chỉ thả giá trị trả về của 'std :: async()' (loại bỏ 'auto i =' trong đoạn mã của tôi), phiên bản 'std :: launch :: deferred' vẫn bị bỏ qua. Điều này không vi phạm "' ~ future' sẽ bị chặn cho đến khi tác vụ hoàn thành "? – timrau

+0

"~ tương lai sẽ chặn cho đến khi tác vụ hoàn tất" không áp dụng trong trường hợp này, vì std :: launch :: hoãn. Đề xuất bạn chọn một bản sao của "Hiệu quả hiện đại C++" của Meyer, xem mục 38. – kfsone

+1

@timrau Lưu ý về chặn '~ tương lai' chỉ áp dụng khi bạn' std :: async (std :: launch :: async'. gọi 'std :: async (std :: launch :: async' mà không lưu trữ giá trị trả về khiến nó bị hủy ở cuối câu lệnh, do đó, luồng chính sẽ bị chặn cho đến khi nhiệm vụ async hoàn thành * trên dòng đó *. Lưu trữ nó trong 'auto i =' sẽ làm cho khối xuất hiện ở cuối phạm vi. Di chuyển 'tương lai' đã trả về sang một' tương lai' khác sẽ trì hoãn khối đó cho đến khi tương lai lưu trữ trạng thái cuối cùng bị hủy. – Yakk

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