Although thinking about it more, and in the context of this thread, the idea of an operation to "raise exception X in thread Y" doesn't seem unreasonable. After all, this is basically what happens to the main thread from the signal handler already; the C signal handler caches a bit that gets picked up by PyErr_CheckSignals(), which raises things like KeyboardInterrupt at completely arbitrary points w.r.t. user code.

One possible approach (at a very schematic level, not thinking about impl details yet) would be to have a function like Thread.raise(e: BaseException) which stuffs the exception into thread-local storage, which then gets checked at similar times to signals. (Probably not the exact same times since I'm sure there's plenty of code depending implicitly on that function being a noop outside the main thread) Basically, it would be having the Python interpreter doing the cooperative part of cross-thread interruption, so that it would look non-cooperative from the user side. You could even have a Thread.raiseWhen to do the equivalent of setting an alarm.

This would definitely be a "use it only if you really mean it" function, but it could be quite useful. Implementing things like watchdog timers is hard right now because of a lack of this sort of feature, but this could open up some nice options.

On Thu, Jun 27, 2019 at 2:17 PM Guido van Rossum <guido@python.org> wrote:
On Thu, Jun 27, 2019 at 1:36 PM Michael Foord <fuzzyman@gmail.com> wrote:

On Thu, 27 Jun 2019 at 20:53, Yonatan Zunger <zunger@humu.com> wrote:
Generally, threads don't have a notion of non-cooperative thread termination. This is because (unlike processes) threads share address spaces, and an unexpected termination of a thread can leave memory in arbitrary and unexpected states. (For example, what if one thread was holding a mutex when it got killed?)

That's precisely why thread cancellation in managed languages (like Python is) raise an exception to terminate the the thread and honour finally blocks. 

There's one issue that Yonatan's post reminded me of though. Currently a thread that's locked in a mutex.acquire() operation cannot be interrupted by a signal at the Python level (unlike I/O, which can be interrupted -- IIRC Victor spent a lot of time making this work). There's a workaround (specify a timeout) but this is still something that would have to be solved for this to be useful.

--
--Guido van Rossum (python.org/~guido)
Pronouns: he/him/his (why is my pronoun here?)