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?
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.
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.
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 ).
std::async returns a std::future<T>, that stores the value returned by function object executed by std::async().
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With