Tags: create, created, ctrl-c, function, invokes, program, programming, python, second, signalhandler, signalsignal, terminates, threadingthread, types, user

threading.Thread vs. signal.signal

On Programmer » Python

4,025 words with 1 Comments; publish: Tue, 06 May 2008 19:09:00 GMT; (20062.50, « »)

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()

All Comments

Leave a comment...

  • 1 Comments
    • On Sat, 17 Sep 2005 19:24:54 -0400, Jack Orenstein <jao.python.todaysummary.com.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 runn

      ing, it can no longer process signals. If you add something like this to th

      e 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

      #1; Tue, 06 May 2008 19:11:00 GMT