Currently, telling a thread to gracefully exit requires setting up some custom signaling mechanism, for example via a
threading.Event. To make this process a bit more efficient, cleaner and simpler, what if some methods were added to:
- Set a soft interruption flag for a specific thread, such as
- Set the interruption flag for all threads, such as
- Query whether the current thread’s interruption flag is set, such as
An example snippet demonstrating the use of these methods:
from time import sleep
from threading import Thread, interruption_requested, interrupt_all_threads
while not interruption_requested():
threads = [Thread(target=loop) for i in range(8)]
for thread in threads:
# tell the first four threads to stop after five seconds
for thread in threads[:4]:
# tell the next four threads to stop after another five seconds
for thread in threads[4:]:
# tell them all to stop if they haven't already
for thread in threads:
Additionally, for convenience, situations such as unhandled SIGHUP, SIGINT/uncaught KeyboardInterrupt or a call to sys.exit in the main thread could automatically set all threads’ interruption flags.
You basically want built-in support for thread cancellation in Python? Something similar, on the Python-level, as pthread_cancel?
Doesn’t ThreadPoolExecutor already achieves that?
Yes, there is
I don’t know all the details of pthread_cancel, so can’t say for sure how much this idea lines up with that.
The main goal of this suggestion is to simplify a common pattern for graceful thread termination. There are multiple questions on stackoverflow regarding this topic. For example:
Most of these answers are a variation of using a
threading.Event or some other shared state to tell the thread that it should exit.
Could you clarify which aspect of ThreadPoolExecutor achieves this and how?
My understanding is that
concurrent.futures.Future.cancel can only stop calls that haven’t yet been executed, and there is no way to query the state of the future from within the call itself to tell whether it has been cancelled. Is that not the case?
Yeah - I don’t know if there is a way to see if the Future was cancelled from within that Future - but that’s a bit of a separate issue, is it not (if you can cancel it conveniently, do you care how)? The ‘cancel’ doc is also a bit ambiguous, but suggests that an executing thread could in principle be cancelled – but I’ve never used that API so don’t know. Anyway - I wonder what the core devs think of your request.
IIUC, what you are suggesting is simply a standardized place and access methods for the recommended practice of a termination flag.
+1 on this.
A possible extension: a check_interrupt() function that polls this flag, and if set raises ThreadExit exception, a subclass of SystemExit. This will let any finally: blocks execute on the way out and possibly caught and cancelled, if you choose to.
Another possible extension: Thread.enable_async_interrupt = True indicates that this thread is not going to poll the interruption flag, but it is ok for interruption to raise ThreadExit exception in the thread.
There is a python C API for this (PyThreadState_SetAsyncExc). It is not exposed to python code by default against “naive misuse”. I suggest that applying it only to threads that opt-in should be sufficient.
Finally, another flag, with the proposed name enable_interrupt_io would enable sending a signal to the thread using signal.pthread_kill() to interrupt any blocking I/O that could otherwise prevent the thread from stopping (+windows equivalent, if possible).
These would all keep the same interface to request interruption of a thread, but opt-in to progressively more intrusive implementations.