[Python-Dev] Interrupting a thread

Guido van Rossum guido@CNRI.Reston.VA.US
Wed, 14 Jul 1999 11:05:04 -0400

> Ive struck this a number of times, and the simple question is "can we make
> it possible to interrupt a thread without the thread's knowledge" or
> otherwise stated "how can we asynchronously raise an exception in another
> thread?"
> The specific issue is that quite often, I find it necessary to interrupt
> one thread from another.  One example is Pythonwin - rather than use the
> debugger hooks as IDLE does, I use a secondary thread.  But how can I use
> that thread to interrupt the code executing in the first? (With magic that
> only works sometimes is how :-)
> Another example came up on the newsgroup recently - discussion about making
> Medusa a true Windows NT Service.  A trivial solution would be to have a
> "service thread", that simply runs Medusa's loop in a seperate thread.
> When the "service thread" recieves a shut-down request from NT, how can it
> interrupt Medusa?
> I probably should not have started with a Medusa example - it may have a
> solution.  Pretend I said "any arbitary script written to run similarly to
> a Unix daemon".  There are one or 2 other cases where I have wanted to
> execute existing code that assumes it runs stand-alone, and can really only
> be stopped with a KeyboardInterrupt.  I can't see a decent way to do this.
> [I guess this ties into the "signals and threads" limitations - I believe
> you cant direct signals at threads either?]
> Is it desirable?  Unfortunately, I can see that it might be hard :-(
> But-sounds-pretty-easy-under-those-fake-threads<wink>-ly,

Hmm...  Forget about signals -- they're twisted Unixisms (even if they 
are nominally supported on NT).

The interesting thing is that you can interrupt the "main" thread
easily (from C) using Py_AddPendingCall() -- this registers a function
that will be invoked by the main thread the next time it gets to the
top of the VM loop.  But the mechanism here was designed with a
specific purpose in mind, and it doesn't allow you to aim at a
specific thread -- it only works for the main thread.  It might be
possible to add an API that allows you to specify a thread id

Of course if the thread to be interrupted is blocked waiting for I/O,
this is not going to interrupt the I/O.  (On Unix, that's what signals
do; is there an equivalent on NT?  I don't think so.)

Why do you say that your magic only works sometimes?  You mailed me
your code once and the Python side of it looks okay to me: it calls
PyErr_SetInterrupt(), which calls Py_AddPendingCall(), which is
threadsafe.  Of course it only works if the thread you try to
interrupt is recognized by Python as the main thread -- perhaps this
is not always under your control, e.g. when COM interferes?

Where is this going?  Is the answer "provide a C-level API like
Py_AddPendingCall() that takes a thread ID" good enough?

Note that for IDLE, I have another problem -- how to catch the ^C
event when Tk is processing events?

--Guido van Rossum (home page: http://www.python.org/~guido/)