Threads and signals
Chad J. Schroeder
chad.schroeder at lodgenet.com
Thu Nov 16 11:20:14 EST 2006
By writing a little C module I fixed the problem. By simply calling
the function in the child thrd's run method, things work as expected.
This is all the function (blockall) does:
sigset_t omask, nmask;
sigfillset(&nmask);
sigprocmask(SIG_SETMASK, &nmask, NULL);
bash-2.05b# python2.5 ./thrd_test.py
Starting up
MainThread.run(): 71799
ChildThread.run(): 71799
ChildThread before sleep(10)
MainThread before sleep(15)
^CReceived signal 2
flag: True
flag: False
MainThread after sleep(15)
Shutting down
bash-2.05b#
Chad
> I've run into an "opportunity" in a Python application using threads
> and signals. Basically, there is a main process that spawns off a child
> thread that loops forever. In between iterations, the child
> thread sleeps for X seconds. All the while, the main thread loops
> forever doing its thing and also sleeps in between iterations (see the code at
> the end this message). Normally the application would
> be daemonized before the main process starts up. Hence, during a
> system shutdown or stoppage of the daemon, it's desired that the
> daemon catch a few signals (TERM/INT) and perform a few cleanup
> routines. According to the Python docs, only the main thread will receive
> signals. The problem I have, on FreeBSD systems, is that the sleep
> function in the child gets interrupted and the signal never gets handled
> until the main thread's sleep concludes. It works as expected on a Linux
> box (main thrd's sleep is interrupted). Sample output from multiple systems
> is directly below.
>
> Just looking for insight from others in the know.
>
> Thanks,
> Chad
>
>
> Linux 2.6.17
> ------------------------------------------------------------------------
> test_bed$ python2.5 ./thrd_test.py
> Starting up
> MainThread.run(): 14332
> MainThread before sleep(15)
> ChildThread.run(): 14332
> ChildThread before sleep(10)
> Received signal 2 <-- Interrupted here (Ctrl-C), correctly
> flag: True interrupts sleep in main thread
> flag: False
> MainThread after sleep(15)
> Shutting down
>
> test_bed$ python2.4 ./thrd_test.py
> Starting up
> MainThread.run(): 14338
> MainThread before sleep(15)
> ChildThread.run(): 14338
> ChildThread before sleep(10)
> Received signal 2 <-- Interrupted here (Ctrl-C), correctly
> flag: True interrupts sleep in main thread
> flag: False
> MainThread after sleep(15)
> Shutting down
> test_bed$
>
> FreeBSD 4.11, 6.1, and 6.2
> ------------------------------------------------------------------------
> bash-2.05b# python2.5 ./thrd_test.py
> Starting up
> MainThread.run(): 65930
> ChildThread.run(): 65930
> ChildThread before sleep(10)
> MainThread before sleep(15)
> ^CChildThread after sleep(10) <-- Interrupted here (Ctrl-C), but
> ChildThread before sleep(10) interrupts the child thrd's sleep
> ChildThread after sleep(10)
> ChildThread before sleep(10)
> Received signal 2 <-- Main sleep concludes and then
> flag: True the signal gets handled
> flag: False
> MainThread after sleep(15)
> Shutting down
> bash-2.05b#
>
>
> #--- CODE BEGIN ---#
>
> #!/usr/bin/env python
>
> import os
> import sys
> import time
> import signal
> import threading
>
> def sigHandle(signo, stkframe):
> print "Received signal ", signo
> print "flag: ", mthrd.flag.isSet()
> mthrd.flag.clear()
> print "flag: ", mthrd.flag.isSet()
>
> class ChildThread(threading.Thread):
>
> def __init__(self):
> threading.Thread.__init__(self)
>
> def run(self):
> print "ChildThread.run(): ", os.getpid()
mymod.blockall()
> while (True):
> print "ChildThread before sleep(10)"
> time.sleep(10)
> print "ChildThread after sleep(10)"
>
> class MainThread(object):
>
> def __init__(self):
> self.flag = threading.Event()
> self.cthrd = ChildThread()
> self.cthrd.setDaemon(True)
>
> def run(self):
> print "MainThread.run(): ", os.getpid()
> self.flag.wait()
> self.cthrd.start()
> while (self.flag.isSet()):
> print "MainThread before sleep(15)"
> time.sleep(15)
> print "MainThread after sleep(15)"
> return # or cleanup routine
>
> if __name__ == "__main__":
>
> # Normally, the process is daemonized first. That's been
> # left out for testing purposes.
>
> signal.signal(signal.SIGINT, sigHandle)
> signal.signal(signal.SIGQUIT, sigHandle)
> signal.signal(signal.SIGTERM, sigHandle)
>
> mthrd = MainThread()
> print "Starting up"
> mthrd.flag.set()
> mthrd.run()
> print "Shutting down"
>
> sys.exit(0)
>
> #--- CODE END ---#
More information about the Python-list
mailing list