except block isn't catching exception

sohcahtoa82 at gmail.com sohcahtoa82 at gmail.com
Fri Aug 7 19:16:14 CEST 2015


On Thursday, August 6, 2015 at 5:46:19 PM UTC-7, Chris Angelico wrote:
> On Fri, Aug 7, 2015 at 10:34 AM,  <sohcahtoa82 at gmail.com> wrote:
> > Despite my "except KeyboardInterrupt", the KeyboardInterrupt forced by the thread.interrupt_main() in the worker thread isn't being caught.
> >
> > Other things worth noting is that the exception takes about 3 seconds after the call to thread.interrupt_main().  It appears to not actually happen until the sock.accept() times out.  If the call to sock.settimeout(5) is removed, the KeyboardInterrupt never appears and flow is still blocked on the sock.accept().
> >
> > My Python version is 2.7.3.  I know its out of date, but I don't really have a choice.
> 
> As far as I know, the only effect of thread.interrupt_main() is to set
> a flag saying "Hey main thread, next time you go checking for these
> things, there's a KeyboardInterrupt waiting for you". It doesn't
> actually send an OS-level signal, which means it cannot interrupt a
> blocking call. So you have a few choices:
> 
> 1) Shorten the timeout on sock.accept() to an (if you'll excuse the
> pun) acceptable delay, and then simply check a flag. Something like
> this:
> 
> interrupt = False
> while not interrupt:
>     try:
>         connection, _ = sock.accept()
>     except socket.timeout:
>         # On timeout, check flag and keep sleeping
>         pass
> 
> If you wish to also have an actual timeout, you could monitor that separately.
> 
> 2) Instead of blocking on sock.accept directly, have another event
> which the other thread can raise, which will wake the main thread. You
> could use select.select() for this.
> 
> 3) Bury the details of select.select() away behind a nice framework
> like asyncio, merge your two threads, and run everything through a
> back-end event loop.
> 
> 4) Use separate processes, and signal the interrupt using an OS-level
> notification (on Unix systems, SIGINT; on Windows, there's an
> equivalent called BreakSignal or something). This will break out of
> the underlying system call that handles accept().
> 
> thread.interrupt_main() is similar to just setting a global that you
> periodically check, except that the periodic check is handled for you
> by the system. That's really all.
> 
> ChrisA

I'll probably go for the first solution.  It's the simplest, and simple is usually good.  In my application, there aren't going to be any consequences for the main thread not unblocking *immediately* when a worker thread requests it.

Though I still doesn't understand why the exception isn't caught when I'm explicitly trying to catch it.  I even tried changing the try/except block to this:

try:
    connection, _ = sock.accept()
except KeyboardInterrupt:
    print 'KeyboardInterrupt caught!'
except socket.timeout:
    print 'Socket timeout caught!'
except:
    print 'other exception caught!'
finally:
    print 'finally!'

The result prints:

Interrupting main
main interrupted!
finally!
Traceback (most recent call last): 
  File "exception_test.py", line 23, in <module> 
    connection, _ = sock.accept() 
KeyboardInterrupt


More information about the Python-list mailing list