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