threading.Thread vs. signal.signal

Jp Calderone exarkun at divmod.com
Sat Sep 17 19:47:58 EDT 2005


On Sat, 17 Sep 2005 19:24:54 -0400, Jack Orenstein <jao at geophile.com> wrote:
>I'd like to create a program that invokes a function once a second,
>and terminates when the user types ctrl-c. So I created a signal
>handler, created a threading.Thread which does the invocation every
>second, and started the thread. The signal handler seems to be
>ineffective. Any idea what I'm doing wrong? This is on Fedora FC4 and
>Python 2.4.1. The code appears below.
>
>If I do the while ... sleep in the main thread, then the signal
>handler works as expected. (This isn't really a satisfactory
>implementation because the function called every second might
>take a significant fraction of a second to execute.)
>
>Jack Orenstein
>
>
>import sys
>import signal
>import threading
>import datetime
>import time
>
>class metronome(threading.Thread):
>     def __init__(self, interval, function):
>         threading.Thread.__init__(self)
>         self.interval = interval
>         self.function = function
>         self.done = False
>
>     def cancel(self):
>         print '>>> cancel'
>         self.done = True
>
>     def run(self):
>         while not self.done:
>             time.sleep(self.interval)
>             if self.done:
>                 print '>>> break!'
>                 break
>             else:
>                 self.function()
>
>def ctrl_c_handler(signal, frame):
>     print '>>> ctrl c'
>     global t
>     t.cancel()
>     sys.stdout.close()
>     sys.stderr.close()
>     sys.exit(0)
>
>signal.signal(signal.SIGINT, ctrl_c_handler)
>
>def hello():
>     print datetime.datetime.now()
>
>t = metronome(1, hello)
>t.start()

The problem is that you allowed the main thread to complete.  No longer running, it can no longer process signals.  If you add something like this to the end of the program, you should see the behavior you wanted:

    while not t.done:
        time.sleep(1)

Incidentally, the last 3 lines of ctrl_c_handler aren't really necessary.

That said, here's a simpler version of the same program, using Twisted:

    import datetime
    from twisted.internet import reactor, task

    def hello():
        print datetime.datetime.now()

    task.LoopingCall(hello).start(1, now=False)
    reactor.run()

Hope this helps!

Jp



More information about the Python-list mailing list