Trong đợt kiểm tra mã, tôi đi qua một đoạn mã mà về cơ bản nắm này:gì sẽ xảy ra khi giao lại cho một tương lai mà không phải là sẵn sàng chưa
#include <iostream>
#include <future>
#include <thread>
int main(int, char **)
{
std::atomic<int> x(0);
std::future<void> task;
for(std::size_t i = 0u; i < 5u; ++i)
{
task = std::async(std::launch::async, [&x, i](){
std::this_thread::sleep_for(std::chrono::seconds(2u * (5u - i)));
++x;
});
}
task.get();
std::cout << x << std::endl;
return 0;
}
Tôi đã không hoàn toàn chắc chắn cho dù
- đảm bảo rằng tất cả các tác vụ được thực hiện khi in kết quả,
- cho dù nhiệm vụ sẽ được thực hiện cái khác (nghĩa là nhiệm vụ sẽ bị chặn) hay không.
Tôi không thể trả lời câu hỏi đó từ đọc tài liệu trên internet, vì vậy tôi nghĩ tôi sẽ viết đoạn mã trên để tìm hiểu trình biên dịch của chúng tôi thực sự làm gì.
Bây giờ, tôi phát hiện ra rằng câu trả lời của gcc-5 là thiếu quyết đoán và điều đó khiến tôi tò mò hơn: Người ta cho rằng nhiệm vụ đó là chặn hoặc không chặn.
Nếu bị chặn, thời gian thực hiện bởi chương trình về cơ bản là tổng thời gian thực hiện các tác vụ riêng lẻ. Người đầu tiên mất 10 giây, thứ hai 8, thứ ba 6, thứ tư 4 và 2 giây cuối cùng. Do đó, tổng cộng sẽ mất 10 + 8 + 6 + 4 + 2 = 30 giây.
Nếu nó không bị chặn, bạn nên thực hiện nhiệm vụ cuối cùng, tức là 2 giây.
Đây là những gì sẽ xảy ra: Phải mất 18 giây (được đo bằng thời gian ./a.out hoặc đồng hồ cũ tốt). Bằng cách chơi xung quanh một chút với mã tôi phát hiện ra rằng mã hoạt động như thể nhiệm vụ sẽ được xen kẽ chặn và không chặn.
Nhưng điều này không thể đúng, phải không? std::async
có thể rơi trở lại std::deferred
một nửa thời gian? Trình gỡ rối của tôi nói rằng nó sinh ra hai luồng, khối cho đến khi cả hai luồng thoát ra, sau đó sinh ra hai luồng nữa và tiếp tục như vậy.
Tiêu chuẩn nói gì? Chuyện gì sẽ xảy ra? Điều gì xảy ra bên trong gcc-5?
Thực tế là mã không mất khoảng thời gian dự kiến hoàn thành là lạ, nhưng điều ** thực sự lạ đối với tôi là giá trị của 'x' được gán đúng 5, trong khi' ngủ ' rõ ràng là không hoàn thành ... – Holt
Bạn thực sự nên in thời gian trôi qua sau khi các cuộc gọi 'sleep' trong lambda của bạn bởi vì bạn sẽ rất ngạc nhiên tôi nghĩ! – Holt
@Holt Việc thực thi 'gcc' đang chặn * đôi khi *, tất cả đều hoạt động trong trường hợp này, nhưng có thể xảy ra sai trong các trường hợp khác. Tôi đã xem nó trong trình gỡ lỗi: 0 bắt đầu, 1 bắt đầu, 1 lần thoát, 0 lần thoát, 2 lần khởi động, 3 lần khởi động, 3 lần thoát, 2 lần thoát, 4 lần khởi động, 4 lần thoát. –