<p>I noticed that many languages' built-in asynchronous <code>Future</code> cannot be canceled once called.</p>
<p>Although many third-party libraries provide this ability, it is not convenient to introduce a third-party library in small scripts.</p>
<p>In fact, there are some languages that do provide a cancel interface, but it does not guarantee that the coroutine will be canceled.</p>
<h4>Languages that must cancel</h4>
<p>unknown</p>
<h4>Languages that may cancel</h4>
<ul>
<li><code>System.Threading.Tasks.Task</code> in C#</li>
<li><code>java.util.concurrent.Future</code> in Java</li>
<li><code>concurrent.futures.Future</code> in Python</li>
<li><code>Concurrent::Promises::Future</code> in Ruby</li>
</ul>
<h4>Languages that cannot cancel</h4>
<ul>
<li><code>Promise</code> in JavaScript</li>
<li><code>std::future::Future</code> in Rust</li>
</ul>
<p>I want to know why these languages do not support cancelling (and guarantee cancelling) the built-in <code>Future</code>?</p>

<async><coroutines>
Why can many languages' futures not be canceled?
CC BY-SA 4.0
2023-07-14T04:19:27.890Z
In Rust, cancellation is done by `drop`ping the future, so you don't need a separate interface for that.
Bubbler
CC BY-SA 4.0
2023-07-14T04:32:27.600Z
@Bubbler Swift does the opposite: dropping a task doesn't cancel it; rather, it means you can no longer cancel it. You have to call the `.cancel()` method manually.
Bbrk24
CC BY-SA 4.0
2023-07-14T05:01:07.233Z
@Bubbler Not everything is cancellation-safe though right? And I don't think there's a built-in way to mark that as the case, you just have to hope the docs are good
rydwolf
CC BY-SA 4.0
2023-07-14T15:04:41.810Z
Java and C# provide mechanisms for canceling the asynchronous computation associated with a given future, but these are not guaranteed to be effective, so Java and C# would be better placed in the "Languages that may cancel" category.
John Bollinger
CC BY-SA 4.0
2023-07-14T18:51:31.567Z
Just to add to what @JohnBollinger said, C# (and presumably Java) have a way to _ask_ a task to cancel, but no way to _force_ it to do so.
Bobson
CC BY-SA 4.0
2023-07-14T19:15:40.787Z
You should have a look at discussions on whether or not to cancel Threads in Java. I've seen it once in practice and we never got it to work completely because the entire code base needs to be aware of cancellation.
feldentm
CC BY-SA 4.0
2023-07-15T01:29:02.387Z
In .NET, the runtime guarantees that if you abort a thread, the *runtime* will not behave badly, but it makes no such guarantee about the *program* not behaving badly as a result. Does that give you any insight into your question?
Eric Lippert
CC BY-SA 4.0
2023-07-16T15:38:51.667Z
I wonder whether this is really a language issue, or depends to at least some extent on the underlying execution environment? Are there any examples where the same language behaves differently depending on whether the target is .NET or unix binary?
Mark Morgan Lloyd
CC BY-SA 4.0
2023-07-16T21:32:49.790Z
What does it _mean_ to guarantee cancellation? If the task you're trying to cancel is running independently in parallel with you, at any given time as you're trying to cancel it, it may be starting or completing. There's no way you can ever guarantee cancellation. (You might respond "but I want to guarantee cancellation if it's still possible!", to which I will answer that such a guarantee is not meaningful or useful, so nobody would make it.)
Glenn Willen
<p>What is a future exactly and what does it mean to cancel it? In C++ you have <a href="https://en.cppreference.com/w/cpp/thread/future" rel="noreferrer"><code>std::future</code></a> objects which merely provide storage for the result of an asynchronous task, and some way to wait for that task to finish. You can just let the <code>std::future</code> object go out of scope without waiting for its result, but that doesn't cancel the task itself.</p>
<p>If you mean &quot;why can many languages' asynchronous <em>tasks</em> not be canceled?&quot;, then again you have to first discuss what a task exactly is. I'll simplify and say there's basically two types: threads and coroutines.</p>
<p>Threads run independent from the main thread. Just cancelling them from the outside is hard, because it is difficult or impossible to predict what that thread is doing at the time it is being cancelled. Maybe it was just locking a mutex? Or it opened a file? You have to ensure that atomic actions are completed, and that any resources that are in use are released correctly. That might require unwinding the stack (as if an exception was thrown). POSIX threads can be cancelled, but only at <a href="https://stackoverflow.com/questions/433989/what-are-the-posix-cancellation-points">cancellation points</a>; C++11 threads don't even bother and don't provide a way to cancel them.</p>
<p>Coroutines are easier to cancel, as there are natural cancellation points from the language itself: every time <code>await</code> or <code>yield</code> is used. They also often run in the same thread, so there are much less thread-safety issues to worry about. For stackless coroutines like in C++20, a coroutine's state is stored in something that is just a <code>class</code>, with that state being stored in member variables. Since destroying objects is well-defined in most languages, destroying an object of that class is easy as well. So in C++ you can just cancel a coroutine by letting the object that stores its state (like C++23's <a href="https://en.cppreference.com/w/cpp/coroutine/generator" rel="noreferrer"><code>std::generator</code></a>) go out of scope.</p>
<p>So in summary: future ≠ task, and whether cancellation is possible depends on the nature of the task. I've also simplified here, there are many variations on threads and coroutines, each with their own implementation details, so you have to look into your language's implementation to find out why cancellation is possible or not.</p>

CC BY-SA 4.0
2023-07-14T12:39:54.787Z
2023-07-14T12:39:54.787Z
G. Sliepen
CC BY-SA 4.0
2023-07-23T19:02:04.117Z
There are more possible kinds of task attached to a `Future` too: you can use them for waiting for operating-system provided asynchronous I/O operations (which are neither threads nor coroutines), Unix signals, or any other kind of asynchronously generated and delivered event.  Whether it is possible to cancel such a Future depends on the type of event source and whether the underlying operating system provides a way of doing so.
occipita
<h1>Requires extra work for implementers of futures</h1>
<p>In languages with futures which aren't expected to be cancellable by default, implementing a future/promise is pretty easy. On the other hand, if cancellation could happen and you're required by the language to handle that correctly, you have to figure out how to properly do that at every point you're waiting, even when it would be a huge problem to cancel there (e.g., in the middle of a filesystem operation that would leave things in an unsafe state; you would have to ignore the cancel and keep working for long enough to fix that, when just mandating &quot;don't cancel during this operation&quot; is far simpler).</p>
<p>It might make sense to have an opt-in way to handle cancelling, which both JS and Rust have, but making futures universally cancellable would be a burden for implementers of futures, especially ones internal to a program/library which the implementer knows for sure won't be cancelled.</p>

CC BY-SA 4.0
2023-07-14T05:15:21.283Z
2023-07-14T05:15:21.283Z
rydwolf
CC BY-SA 4.0
2023-07-14T05:48:05.993Z
I think you are misunderstanding how cancellation works. You can't, in general, cancel any IO operation without specific code to handle that. Instead, promise cancellation normally works by simply discarding the result of the IO operation inside user code. Race conditions can happen but only inside user code not IO, and then only at the end point of an IO operation.
mousetail 'he-him'
CC BY-SA 4.0
2023-07-14T05:52:06.977Z
Additionally, languages that allow cancellation typically have [something like python's shield()](https://docs.python.org/3/library/asyncio-task.html#asyncio.shield) that allow precise control over when a task is allowed to cancel and when it is not
mousetail 'he-him'
<h3>Destroy at distance is hard, and probably wrong</h3>
<p>Take for example this: <code>cat file | uniq | sort</code>.</p>
<p>That is, <code>cat</code> output is a future of <code>uniq</code>, and <code>uniq</code> output is a future of <code>sort</code>. So now <code>sort</code> wants to <em>immediately interrupt and destroy</em> all its pending futures. In this simple example there is no problem.</p>
<p>But if instead of <code>cat</code> there is <code>malloc</code>ed structure, passed to the kernel, where you are writing (cancel or <code>free</code>ing) at the same time the kernel is writing. Boom happens.</p>
<p>It would be very simple to reason if cancellation acted immediately, but this really means that the future needs to be guarded against this type of &quot;two writers at same time&quot; type of problem.</p>
<p>This <strong>is possible</strong> in a <code>MutexFuture</code>, but... futures are normally utilized on code where performance is paramount. You are already trading performance for a heap allocation. Adding a lock in every action will cancel these performance gains (pun intended).</p>
<p>Because of these trade offs that cancel only &quot;signal&quot; the cancellation of one writer, leaving runtime or the other writer to do the right thing later on, with no locks in the hot path.</p>

CC BY-SA 4.0
2023-07-14T15:09:12.593Z
2023-07-14T15:09:12.593Z
André L F S Bacci
<p>Briefly: Cancellation done that way is a global contract because the asynchronous operation can be anywhere in your code base. If you wan't a local contract, you need to use some other communication channel and something like safe zones where you check as asynchronous operation if you should continue. In that way, there is no difference between Futures and Threads. You can start digging <a href="https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/lang/Thread.html#stop()" rel="nofollow noreferrer">here</a>.</p>

CC BY-SA 4.0
2023-07-14T19:23:08.240Z
2023-07-14T19:23:08.240Z
feldentm
<p>The problem with canceling a concurrent execution that runs on another thread is that you don't know what state it is in. It is very well possible that it is currently in a phase where just interrupting it without warning can lead to bad stuff happening. Half-written files, hanging database transactions, leaked memory, locks remaining taken etc.</p>
<p>The naive solution to this problem would be to give futures the ability to perform cleanups when canceled. But that's not unproblematic either:</p>
<ol>
<li>You no longer  know if canceling a future <em>really</em> cancels it. The cleanup procedure of the future will keep running, and might continue doing work you actually wanted to prevent from happening.</li>
<li>The implementation of the future doesn't know when it might get canceled. So it would have to be able to handle being canceled in every conceivable step of its execution. That's often not feasible.</li>
</ol>
<p>However, if someone really needs canceling, then they can usually implement that on their own using whatever features your language supports for communicating between threads. In that case the canceling needs to be implemented on the side of the future. The future needs to actively listen to a cancellation signal, and then actively end itself in a controlled manner. So the programmer should know what state they are in and what they need to do if canceled in that state.</p>

CC BY-SA 4.0
2023-07-14T10:17:31.403Z
2023-07-14T10:28:29.723Z
2023-07-14T10:28:29.723Z
Philipp
CC BY-SA 4.0
2023-07-15T03:05:06.853Z
Although it is impossible to cancel when the operation is blocked, can I check at each await point
Aster
CC BY-SA 4.0
2023-07-15T08:20:24.883Z
@Aster I would not recommend it, because an operation that must not be interrupted might include several await-points internally.
Philipp
CC BY-SA 4.0
2023-07-15T20:54:14.170Z
"The cleanup procedure of the future will keep running, and might continue doing work you actually wanted to prevent from happening." - well, *did* you actually want to prevent that work from happening? It certainly depends on what you want to achieve by canceling. Naively, I'd say that at least one use case is "I don't care for this action anymore. Make it do as little work as is still necessary before terminating it." If that is the chosen semantic for canceling, then, *yes*, the future is *really* canceled even if this means it keeps running for another minute (instead of the 5 it would ...
O. R. Mapper
CC BY-SA 4.0
2023-07-15T20:54:39.587Z
... have taken, hadn't it been canceled). Likewise, problem 2 would be a moot point, because depending on the type and state of the future, it would indeed be expected that canceling doesn't actually have an effect on the future itself. The point would be "Do what you must, but try to stop as early as possible."
O. R. Mapper
CC BY-SA 4.0
2023-07-16T17:28:06.823Z
Trying to have a "cancel" method which is guaranteed to leave things in a consistent state would likely be expensive, but I would think it might still be useful to have a means of telling a future that the task it was created to perform has become *useless*, and additional effort expended performing that task will be wasted.
supercat
CC BY-SA 4.0
2023-07-16T20:42:56.397Z
You can also implement futures on your own using whatever features your language supports for communicating between threads. So if we follow this logic we should also get rid of futures. But in reality we keep them because they are useful, and we should have cancellable futures too, if they are useful.
Criticize SE actions means ban
CC BY-SA 4.0
2023-07-23T09:45:10.847Z
In short: the same reason that many languages' *threads* don't offer a *stop* feature.
Karl Knechtel
# Why can many languages' futures not be canceled?
Posted by: username_0 on 2023-07-14
I noticed that many languages' built-in asynchronous `Future` cannot be canceled once called.

Although many third-party libraries provide this ability, it is not convenient to introduce a third-party library in small scripts.

In fact, there are some languages that do provide a cancel interface, but it does not guarantee that the coroutine will be canceled.

#### Languages that must cancel

unknown

#### Languages that may cancel

* `System.Threading.Tasks.Task` in C#
* `java.util.concurrent.Future` in Java
* `concurrent.futures.Future` in Python
* `Concurrent::Promises::Future` in Ruby

#### Languages that cannot cancel

* `Promise` in JavaScript
* `std::future::Future` in Rust

I want to know why these languages do not support cancelling (and guarantee cancelling) the built-in `Future`?
**Tags:** async coroutines
> **Comments:**
> **username_1**: In Rust, cancellation is done by `drop`ping the future, so you don't need a separate interface for that.  
> **username_2**: @Bubbler Swift does the opposite: dropping a task doesn't cancel it; rather, it means you can no longer cancel it. You have to call the `.cancel()` method manually.  
> **username_3**: @Bubbler Not everything is cancellation-safe though right? And I don't think there's a built-in way to mark that as the case, you just have to hope the docs are good  
> **username_4**: Java and C# provide mechanisms for canceling the asynchronous computation associated with a given future, but these are not guaranteed to be effective, so Java and C# would be better placed in the "Languages that may cancel" category.  
> **username_5**: Just to add to what @JohnBollinger said, C# (and presumably Java) have a way to _ask_ a task to cancel, but no way to _force_ it to do so.  
> **username_6**: You should have a look at discussions on whether or not to cancel Threads in Java. I've seen it once in practice and we never got it to work completely because the entire code base needs to be aware of cancellation.  
> **username_7**: In .NET, the runtime guarantees that if you abort a thread, the *runtime* will not behave badly, but it makes no such guarantee about the *program* not behaving badly as a result. Does that give you any insight into your question?  
> **username_8**: I wonder whether this is really a language issue, or depends to at least some extent on the underlying execution environment? Are there any examples where the same language behaves differently depending on whether the target is .NET or unix binary?  
> **username_9**: What does it _mean_ to guarantee cancellation? If the task you're trying to cancel is running independently in parallel with you, at any given time as you're trying to cancel it, it may be starting or completing. There's no way you can ever guarantee cancellation. (You might respond "but I want to guarantee cancellation if it's still possible!", to which I will answer that such a guarantee is not meaningful or useful, so nobody would make it.)  
---
## 5 answers
### Answer by username_14 on 2023-07-14. Score: 24 | Accepted answer
The problem with canceling a concurrent execution that runs on another thread is that you don't know what state it is in. It is very well possible that it is currently in a phase where just interrupting it without warning can lead to bad stuff happening. Half-written files, hanging database transactions, leaked memory, locks remaining taken etc.

The naive solution to this problem would be to give futures the ability to perform cleanups when canceled. But that's not unproblematic either:

1. You no longer know if canceling a future *really* cancels it. The cleanup procedure of the future will keep running, and might continue doing work you actually wanted to prevent from happening.
2. The implementation of the future doesn't know when it might get canceled. So it would have to be able to handle being canceled in every conceivable step of its execution. That's often not feasible.

However, if someone really needs canceling, then they can usually implement that on their own using whatever features your language supports for communicating between threads. In that case the canceling needs to be implemented on the side of the future. The future needs to actively listen to a cancellation signal, and then actively end itself in a controlled manner. So the programmer should know what state they are in and what they need to do if canceled in that state.
> **Comments:**
> **username_0** (2023-07-15): Although it is impossible to cancel when the operation is blocked, can I check at each await point  
> **username_14** (2023-07-15): @Aster I would not recommend it, because an operation that must not be interrupted might include several await-points internally.  
> **username_15** (2023-07-15): "The cleanup procedure of the future will keep running, and might continue doing work you actually wanted to prevent from happening." - well, *did* you actually want to prevent that work from happening? It certainly depends on what you want to achieve by canceling. Naively, I'd say that at least one use case is "I don't care for this action anymore. Make it do as little work as is still necessary before terminating it." If that is the chosen semantic for canceling, then, *yes*, the future is *really* canceled even if this means it keeps running for another minute (instead of the 5 it would ...  
> **username_15** (2023-07-15): ... have taken, hadn't it been canceled). Likewise, problem 2 would be a moot point, because depending on the type and state of the future, it would indeed be expected that canceling doesn't actually have an effect on the future itself. The point would be "Do what you must, but try to stop as early as possible."  
> **username_16** (2023-07-16): Trying to have a "cancel" method which is guaranteed to leave things in a consistent state would likely be expensive, but I would think it might still be useful to have a means of telling a future that the task it was created to perform has become *useless*, and additional effort expended performing that task will be wasted.  
> **username_17** (2023-07-16): You can also implement futures on your own using whatever features your language supports for communicating between threads. So if we follow this logic we should also get rid of futures. But in reality we keep them because they are useful, and we should have cancellable futures too, if they are useful.  
> **username_18** (2023-07-23): In short: the same reason that many languages' *threads* don't offer a *stop* feature.  
---
### Answer by username_10 on 2023-07-14. Score: 14
What is a future exactly and what does it mean to cancel it? In C++ you have [`std::future`](https://en.cppreference.com/w/cpp/thread/future) objects which merely provide storage for the result of an asynchronous task, and some way to wait for that task to finish. You can just let the `std::future` object go out of scope without waiting for its result, but that doesn't cancel the task itself.

If you mean "why can many languages' asynchronous *tasks* not be canceled?", then again you have to first discuss what a task exactly is. I'll simplify and say there's basically two types: threads and coroutines.

Threads run independent from the main thread. Just cancelling them from the outside is hard, because it is difficult or impossible to predict what that thread is doing at the time it is being cancelled. Maybe it was just locking a mutex? Or it opened a file? You have to ensure that atomic actions are completed, and that any resources that are in use are released correctly. That might require unwinding the stack (as if an exception was thrown). POSIX threads can be cancelled, but only at [cancellation points](https://stackoverflow.com/questions/433989/what-are-the-posix-cancellation-points); C++11 threads don't even bother and don't provide a way to cancel them.

Coroutines are easier to cancel, as there are natural cancellation points from the language itself: every time `await` or `yield` is used. They also often run in the same thread, so there are much less thread-safety issues to worry about. For stackless coroutines like in C++20, a coroutine's state is stored in something that is just a `class`, with that state being stored in member variables. Since destroying objects is well-defined in most languages, destroying an object of that class is easy as well. So in C++ you can just cancel a coroutine by letting the object that stores its state (like C++23's [`std::generator`](https://en.cppreference.com/w/cpp/coroutine/generator)) go out of scope.

So in summary: future ≠ task, and whether cancellation is possible depends on the nature of the task. I've also simplified here, there are many variations on threads and coroutines, each with their own implementation details, so you have to look into your language's implementation to find out why cancellation is possible or not.
> **Comments:**
> **username_11** (2023-07-23): There are more possible kinds of task attached to a `Future` too: you can use them for waiting for operating-system provided asynchronous I/O operations (which are neither threads nor coroutines), Unix signals, or any other kind of asynchronously generated and delivered event.  Whether it is possible to cancel such a Future depends on the type of event source and whether the underlying operating system provides a way of doing so.  
---
### Answer by username_3 on 2023-07-14. Score: 9
# Requires extra work for implementers of futures

In languages with futures which aren't expected to be cancellable by default, implementing a future/promise is pretty easy. On the other hand, if cancellation could happen and you're required by the language to handle that correctly, you have to figure out how to properly do that at every point you're waiting, even when it would be a huge problem to cancel there (e.g., in the middle of a filesystem operation that would leave things in an unsafe state; you would have to ignore the cancel and keep working for long enough to fix that, when just mandating "don't cancel during this operation" is far simpler).

It might make sense to have an opt-in way to handle cancelling, which both JS and Rust have, but making futures universally cancellable would be a burden for implementers of futures, especially ones internal to a program/library which the implementer knows for sure won't be cancelled.
> **Comments:**
> **username_12** (2023-07-14): I think you are misunderstanding how cancellation works. You can't, in general, cancel any IO operation without specific code to handle that. Instead, promise cancellation normally works by simply discarding the result of the IO operation inside user code. Race conditions can happen but only inside user code not IO, and then only at the end point of an IO operation.  
> **username_12** (2023-07-14): Additionally, languages that allow cancellation typically have [something like python's shield()](https://docs.python.org/3/library/asyncio-task.html#asyncio.shield) that allow precise control over when a task is allowed to cancel and when it is not  
---
### Answer by username_13 on 2023-07-14. Score: 2
### Destroy at distance is hard, and probably wrong

Take for example this: `cat file | uniq | sort`.

That is, `cat` output is a future of `uniq`, and `uniq` output is a future of `sort`. So now `sort` wants to *immediately interrupt and destroy* all its pending futures. In this simple example there is no problem.

But if instead of `cat` there is `malloc`ed structure, passed to the kernel, where you are writing (cancel or `free`ing) at the same time the kernel is writing. Boom happens.

It would be very simple to reason if cancellation acted immediately, but this really means that the future needs to be guarded against this type of "two writers at same time" type of problem.

This **is possible** in a `MutexFuture`, but... futures are normally utilized on code where performance is paramount. You are already trading performance for a heap allocation. Adding a lock in every action will cancel these performance gains (pun intended).

Because of these trade offs that cancel only "signal" the cancellation of one writer, leaving runtime or the other writer to do the right thing later on, with no locks in the hot path.
---
### Answer by username_6 on 2023-07-14. Score: 1
Briefly: Cancellation done that way is a global contract because the asynchronous operation can be anywhere in your code base. If you wan't a local contract, you need to use some other communication channel and something like safe zones where you check as asynchronous operation if you should continue. In that way, there is no difference between Futures and Threads. You can start digging [here](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/lang/Thread.html#stop()).
---
