Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I cancel a std::async function? [duplicate]

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

There is a member function which runs asynchronously using std::future and std::async. In some case, I need to cancel it. (The function loads near objects consecutively and sometimes an objects gets out of range while loading it.) I already read the answers to this question addressing the same issue, but I cannot get it work.

This is simplified code with the same structure as my actual program has. Calling Start() and Kill() while the asynchronous is running, causes a crash because of access violation for input.

In my eyes the code should work as follows. When Kill() is called, the running flag is disabled. The next command get() should wait for thread to end, which it does soon since it checks the running flag. After the thread is canceled, the input pointer is deleted.

#include <vector>
#include <future>
using namespace std;

class Class
{
    future<void> task;
    bool running;
    int *input;
    vector<int> output;

    void Function()
    {
        for(int i = 0; i < *input; ++i)
        {
            if(!running) return;
            output.push_back(i);
        }
    }

    void Start()
    {
        input = new int(42534);
        running = true;
        task = async(launch::async, &Class::Function, this);
    }

    void Kill()
    {
        running = false;
        task.get();
        delete input;
    }
};

It seems like the thread doesn't notice toggling the running flag to false. What is my mistake?

like image 444
danijar Avatar asked Jan 13 '13 14:01

danijar


People also ask

How do I cancel async STD?

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.

Does std:: async use a thread pool?

MSVC creates a thread pool the first time you run std::async , which may become an overhead in certain situations. The difference in the implementations may lead to unexpected behavior after the code is ported between GCC/LLVM and MSVC.

How std:: async works?

std::async. Calls fn (with args as arguments) at some point, returning without waiting for the execution of fn to complete. The value returned by fn can be accessed through the future object returned (by calling its member future::get ).

What does STD async return?

std::async returns a std::future<T>, that stores the value returned by function object executed by std::async().


1 Answers

Since noone's actually answered the question yet I'll do so.

The writes and reads to the running variable are not atomic operations, so there is nothing in the code that causes any synchronisation between the two threads, so nothing ever ensures that the async thread sees that the variable has changed.

One possible way that can happen is that the compiler analyzes the code of Function, determines that there are never any writes to the variable in that thread, and as it's not an atomic object writes by other threads are not required to be visible, so it's entirely legal to rearrange the code to this:

void Function()
{
    if(!running) return;
    for(int i = 0; i < *input; ++i)
    {
        output.push_back(i);
    }
}

Obviously in this code if running changes after the function has started it won't cause the loop to stop.

There are two ways the C++ standard allows you to synchronize the two threads, which is either to use a mutex and only read or write the running variable while the mutex is locked, or to make the variable an atomic variable. In your case, changing running from bool to atomic<bool> will ensure that writes to the variable are synchronized with reads from it, and the async thread will terminate.

like image 182
Jonathan Wakely Avatar answered Oct 15 '22 17:10

Jonathan Wakely