I'm trying to track down an issue with a multi-threaded program that is responsible for handling real-time monitoring a business process. Different threads track various aspects of the process and all of the statistics filter back to the main thread for analysis. The program is run as a scheduled task, and various stats are shown in the console window ("dos box") as it runs. Normally the main thread tells the worker threads to stop (using an Event()) when the work is done.
I just recently added some signal handlers to the program to send out an email if someone comes along and closes the console window. (BTW, sometimes closing the app is legitimate, so I don't want to just disable it or run the process in the background) I'm running into this issue on Windows with the follow exception at the time when the signal handler is called: Traceback (most recent call last): ... self.done.wait(30) File "D:\Python24\lib\threading.py", line 348, in wait self.__cond.wait(timeout) File "D:\Python24\lib\threading.py", line 222, in wait _sleep(delay) IOError: [Errno 4] Interrupted function call I do development work on both Linux and Windows, and Linux doesn't seem to behave this way. I'm careful to make sure that the signal handler only directly interacts with the main thread to be safe, but the must be something I'm missing. I took a simple threading example and modified to demonstrate the problem. It fails the same way, every time I run it on Windows, and it works find each time on Linux. I temporarly stuck in a try/except block to just ignore IOErrors, but that seems like a faulty approach. I would have to add try/except block everywhere I call anything that could potentially call sleep(), which seems like a poor (and painful) solution. I also thought about replacing threading._sleep with a try/except wrapper function, but that seems kind of evil. Thanks in advance for any suggestions, Lowell Alleman ----------------- import threading import signal import time, random class Counter: def __init__(self): self.lock = threading.Lock() self.value = 0 def increment(self): self.lock.acquire() self.value = value = self.value + 1 self.lock.release() return value class Worker(threading.Thread): def __init__(self): self.done = threading.Event() threading.Thread.__init__(self) def run(self): while not self.done.isSet(): # pretend we're doing something that takes 10-100 ms value = counter.increment() # increment global counter time.sleep(random.randint(10, 100) / 1000.0) print self.getName(), "-- task", i, "finished", value def stop(self): self.done.set() def handler(sig, frame): print "Signal handler. Sig=%r" % sig global workers for w in workers: w.stop() counter = Counter() workers = [ Worker() for i in range(10) ] for w in workers: w.start() # Install my custom signal handler which tells worker threads to stop try: # Win32 signal.signal(signal.SIGBREAK, handler) except: # Linux signal.signal(signal.SIGTERM, handler) signal.signal(signal.SIGINT, handler) print "Please press Ctrl-C/Ctrl-Break or close the console window now..." # Main thread sleeps waiting for work to be done... time.sleep(60) # Wait for all workers to finish print "Stop All workers!" for w in workers: w.stop() print "Joining all workers to main!" for w in workers: w.join() ----------------- Traceback (most recent call last): File "python_thread_signal_issue.py", line 45, in ? time.sleep(60) IOError: [Errno 4] Interrupted function call -- http://mail.python.org/mailman/listinfo/python-list