On Thursday, June 27, 2019, 03:40:56 PM PDT, Yonatan Zunger
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.
You could build a hacky version of this today in just a few lines, something like this: class AbortableThread(threading.Thread): def __init__(self, *args, **kw): super().__init__(*args, **kw) self._e = None def _trace(self, frame, event, arg): if self._e: raise self._e() return self._trace def run(self, *args, **kw): sys.settrace(self._trace) super().run(*args, **kw) def throw(self, e): self._e = e You wouldn't want to do this in practice, but for playing with the API to see if it feels right/usable, it should be fine.