views:

440

answers:

5

In my program I have a bunch of threads running and I'm trying to interrupt the main thread to get it to do something asynchronously. So I set up a handler and send the main process a SIGUSR1 - see the code below:

def SigUSR1Handler(signum, frame):

    self._logger.debug('Received SIGUSR1')

    return

signal.signal(signal.SIGUSR1, SigUSR1Handler)

[signal.signal(signal.SIGUSR1, signal.SIG_IGN)]

In the above case, all the threads and the main process stops - from a 'c' point of view this was unexpected - I want the threads to continue as they were before the signal. If I put the SIG_IGN in instead, everything continues fine.

Can somebody tell me how to do this? Maybe I have to do something with the 'frame' manually to get back to where it was..just a guess though thanks in advance,

+1  A: 

Mixing signals and threads is always a little precarious. What you describe should not happen, however. Python only handles signals in the main thread. If the OS delivered the signal to another thread, that thread may be briefly interrupted (when it's performing, say, a systemcall) but it won't execute the signal handler. The main thread will be asked to execute the signalhandler at the next opportunity.

What are your threads (including the main thread) actually doing when you send the signal? How do you notice that they all 'stop'? Is it a brief pause (easily explained by the fact that the main thread will need to acquire the GIL before handling the signal) or does the process break down entirely?

Thomas Wouters
A: 

You should probably use a threading.Condition variable instead of sending signals. Have your main thread check it every loop and perform its special operation if it's been set.

If you insist on using signals, you'll want to move to using subprocess instead of threads, as your problem is likely due to the GIL.

Jorenko
A: 

Thanks for your help on this.

To explain a bit more, I have thread instances writing string information to a socket which is also output to a file. These threads run their own timers so they independently write their outputs to the socket. When the program runs I also see their output on stdout but it all stops as soon as I see the debug line from the signal.

I need the threads to constantly send this info but I need the main program to take a command so it also starts doing something else (in parallel) for a while. I thought I'd just be able to send a signal from the command line to trigger this.

SJA
+1  A: 

I'll sort-of answer my own question: In my first attempt at this I was using time.sleep(run_time) in the main thread to control how long the threads ran until they were stopped. By adding debug I could see that the sleep loop seemed to be exiting as soon as the signal handler returned so everything was shutting down normally but early!

I've replaced the sleep with a while loop and that doesn't jump out after the signal handler returns so my threads keep running. So it solves the problem but I'm still a bit puzzled about sleep()'s behaviour.

SJA
A: 

Watch this presentation by David Beazley.

http://blip.tv/file/2232410

It also explains some quirky behavior related to threads and signals (Python specific, not the general quirkiness of the subject :-) ).

http://pyprocessing.berlios.de/ Pyprocessing is a neat library that makes it easier to work with separate processes in Python.

Miron Brezuleanu