Is there a way to cancel/detach a future in C++11?

I have the following code:

#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";
}

This is supposed to wait 1 second, print "Timeout", and exit. Instead of exiting, it waits an additional 9 seconds, prints "Sleeping Done", and then segfaults. Is there a way to cancel or detach the future so my code will exit at the end of main instead of waiting for the future to finish executing?


Solution 1:

The C++11 standard does not provide a direct way to cancel a task started with std::async. You will have to implement your own cancellation mechanism, such as passing in an atomic flag variable to the async task which is periodically checked.

Your code should not crash though. On reaching the end of main, the std::future<int> object held in result is destroyed, which will wait for the task to finish, and then discard the result, cleaning up any resources used.

Solution 2:

Here a simple example using an atomic bool to cancel one or multiple future at the same time. The atomic bool may be wrapped inside a Cancellation class (depending on taste).

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

Solution 3:

I know this is an old question, but it still comes up as the top result for "detach std::future" when searching. I came up with a simple template based approach to handle this:

template <typename RESULT_TYPE, typename FUNCTION_TYPE>
std::future<RESULT_TYPE> startDetachedFuture(FUNCTION_TYPE func) {
    std::promise<RESULT_TYPE> pro;
    std::future<RESULT_TYPE> fut = pro.get_future();

    std::thread([func](std::promise<RESULT_TYPE> p){p.set_value(func());},
                std::move(pro)).detach();

    return fut;
}

and you use it like so:

int main(int argc, char ** argv) {
    auto returner = []{fprintf(stderr, "I LIVE!\n"); sleep(10); return 123;};

    std::future<int> myFuture = startDetachedFuture<int, decltype(returner)>(returner);
    sleep(1);
}

output:

$ ./a.out 
I LIVE!
$

If myFuture goes out of scope and is destructed, the thread will carry on doing whatever it was doing without causing problems because it owns the std::promise and its shared state. Good for occasions where you only sometimes would prefer to ignore the result of a computation and move on (my use case).

To the OP's question: if you get to the end of main it will exit without waiting for the future to finish.

This macro is unnecessary but saves on typing if you are going to call this frequently.

// convenience macro to save boilerplate template code
#define START_DETACHED_FUTURE(func) \
    startDetachedFuture<decltype(func()), decltype(func)>(func)

// works like so:
auto myFuture = START_DETACHED_FUTURE(myFunc);