Есть ли способ отменить/отделить будущее на С++ 11?
У меня есть следующий код:
#include <iostream>
#include <future>
#include <chrono>
#include <thread>
using namespace std;
int sleep_10s()
{
this_thread::sleep_for(chrono::seconds(10));
cout << "Sleeping Done\n";
return 3;
}
int main()
{
auto result=async(launch::async, sleep_10s);
auto status=result.wait_for(chrono::seconds(1));
if (status==future_status::ready)
cout << "Success" << result.get() << "\n";
else
cout << "Timeout\n";
}
Ожидается 1 секунда, печать "Тайм-аут" и выход. Вместо выхода, он ждет еще 9 секунд, печатает "Sleeping Done", а затем segfaults. Есть ли способ отменить или отделить будущее, чтобы мой код выходил в конце main, а не ожидал, что будущее закончит выполнение?
Ответы
Ответ 1
Стандарт С++ 11 не предоставляет прямого способа отменить задачу, начатую с std::async
. Вам придется реализовать свой собственный механизм отмены, например, передать переменную атомного флага в задачу async, которая периодически проверяется.
Однако ваш код не должен вылетать. По достижении конца main
объект std::future<int>
, хранящийся в result
, будет уничтожен, что будет ждать завершения задачи, а затем отбросить результат, очистить все используемые ресурсы.
Ответ 2
Вот простой пример использования атомарного bool для одновременного отмены одного или нескольких будущих. Атомный bool может быть обернут внутри класса Cancellation (в зависимости от вкуса).
#include <chrono>
#include <future>
#include <iostream>
using namespace std;
int long_running_task(int target, const std::atomic_bool& cancelled)
{
// simulate a long running task for target*100ms,
// the task should check for cancelled often enough!
while(target-- && !cancelled)
this_thread::sleep_for(chrono::milliseconds(100));
// return results to the future or raise an error
// in case of cancellation
return cancelled ? 1 : 0;
}
int main()
{
std::atomic_bool cancellation_token;
auto task_10_seconds= async(launch::async,
long_running_task,
100,
std::ref(cancellation_token));
auto task_500_milliseconds = async(launch::async,
long_running_task,
5,
std::ref(cancellation_token));
// do something else (should allow short task
// to finish while the long task will be cancelled)
this_thread::sleep_for(chrono::seconds(1));
// cancel
cancellation_token = true;
// wait for cancellation/results
cout << task_10_seconds.get() << " "
<< task_500_milliseconds.get() << endl;
}