How to stop a std::async task

By , last updated June 24, 2019

Sadly, this is only an intrusive way of stopping std::async. For an almost non-intrusive way of stopping a thread, look at boost::thread.

Read also: Simple threading with std::async

Here the task is to check for primes, in a very non-optimized way consuming as much time as possible. The idea is to pass in an std::atomic_bool, which acts as an interruption point for this particular task.

#include <iostream>       // std::cout
#include <future>         // std::async, std::future
#include <chrono>         // std::chrono::milliseconds  

// a _very_ non-optimized way of checking for prime numbers:
bool is_prime(int x, std::atomic_bool & run)
{
    for (int i = 2; i < x; ++i)
    {
        if (!run)
        {
            throw std::runtime_error("timeout");
        }

        if (x%i == 0)
            return false;
    }

    return true;
}

int main()
{
    // call function asynchronously:
    std::atomic_bool run;
    run = true;

    // Pass the atomic boolean as reference
    std::future<bool> fut = std::async(is_prime, 96718939, std::ref(run));

    // do something while waiting for function to set future:
    std::cout << "checking, please wait";
    std::chrono::milliseconds span(100);
    if (fut.wait_for(span) == std::future_status::timeout)
    {
        // Set the running state to false, terminating the thread with an exception
        run = false;
    }

    try
    {
        bool x = fut.get();
        std::cout << "n96718939 " << (x ? "is" : "is not") << " prime.n";
    }
    catch (const std::runtime_error & ex)
    {
        // Handle timeout here
        std::cout << "Got timeout...";
    }

    return 0;
}

There are probably better ways to interrupt other threads, but this is the most simplest and not-so-very elegant.

But the intention is clear.

The problem with stopping another threads with C++ non-intrusively.

Stopping threads at an arbitrary point is dangerous and will lead to resource leaks, where resources being pointers, handles to files and folders, and other things the program should do.

When killing a thread, the thread may or may not be doing work. Whatever it was doing, it won’t get to complete and any variables successfully created will not get their destructors called because there is no thread to run them on.

The most clean way is to use interruption points, where you, The Programmer, can insert safe points where the interruption may occur. Then, if interruptions are enabled and an interruption is pending, it will throw an exception. With smart pointers holding resources, there will be no resources leaks. Any successfully created object (on the stack) will be destructed when unwinding the exception, and it will continue unwinding until it hits the thread handler, who knows what exception to look for (and rethrow other exceptions). This is how I believe boost::thread is implemented.