Educating yourself does not mean that you were stupid in the first place; it means that you are intelligent enough to know that there is plenty left to 'learn'. -Melanie Joy

Saturday, 4 January 2014

Python - Thread synchronization - using Thread Events

January 04, 2014 Posted by Dinesh No comments
We may often need to signal the thread to do some special task. Simple solution is to create events.

Definition from python docs:
threading.Event()
    A factory function that returns a new event object. An event manages a flag that can be set to true with the set() method and reset to false with the clear() method. The wait() method blocks until the flag is true 

the event represents an internal flag, and threads can wait for the flag to be set, or set or clear the flag themselves. The methods provided are very much self explanatory: set() clear() isSet() wait(timeout)
This is a simple mechanism. A thread signals an event and the other thread(s) wait for it.

In the following example we are crating an event and a thread,  and passing that event to the thread function. that thread function is waiting on that event. if user press ctrl+c then it is caught in the main program by keyboardInterrup and we are setting the stop event. This even cause the while in the thread function to break and exits the thread.


#!/usr/bin/python
import threading,time

def collectstats(event):
    while not event.is_set():
          event.wait(1)
    print "event set.. thread exiting.."

stop_event = threading.Event()
th = threading.Thread(target=collectstats, args=(stop_event,))
th.start()

while True:
    try:
        time.sleep(100)
    except KeyboardInterrupt as e:
        stop_event.set()
        th.join()
        break;

print "in main: exiting.."

if we run the program, here is the output


# ./even.py 

^Cevent set.. thread exiting..
in main: exiting..

Any number of threads can wait on same event and can set same event. once the even is set it will notify all the threads ( equivalent to notifyall() method )

Friday, 3 January 2014

Python - Signal handling and identifying stack frame

January 03, 2014 Posted by Dinesh No comments
Signals are identified by integers and are defined in the operating system C headers. Python exposes the signals appropriate for the platform as symbols in the 'signal' module. 

the signal module in python is used to install your own signal handlers.  When the interpreter sees a signal, the signal handler associated with that signal is executed as soon as possible.

signal handler is a call back function, the arguments to the signal handler are the signal number and the stack frame from the point in your program that was interrupted by the signal. 

First basic example:

import signal,time

def signal_handler(signum, stack):
    print 'Received:', signum

signal.signal(signal.SIGHUP, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(15, signal_handler)
while True: print 'Waiting...try kill using signal 1(SIGHUP) or 2(SIGINT)' time.sleep(3)


Linux Standard signals:
from signal man page:
       Signal     Value     Action   Comment
       -------------------------------------------------------------------------
       SIGHUP        1       Term    Hangup detected on controlling terminal or death of controlling process
       SIGINT        2        Term    Interrupt from keyboard
       SIGQUIT       3      Core    Quit from keyboard
       SIGILL        4        Core    Illegal Instruction
       SIGABRT       6      Core    Abort signal from abort(3)
       SIGFPE        8       Core    Floating point exception
       SIGKILL       9       Term    Kill signal
       SIGSEGV      11     Core    Invalid memory reference
       SIGPIPE      13      Term    Broken pipe: write to pipe with no readers
       SIGALRM      14       Term    Timer signal from alarm(2)
       SIGTERM      15       Term    Termination signal
       SIGUSR1   30,10,16    Term    User-defined signal 1
       SIGUSR2   31,12,17    Term    User-defined signal 2
       SIGCHLD   20,17,18    Ign     Child stopped or terminated
       SIGCONT   19,18,25    Cont    Continue if stopped
       SIGSTOP   17,19,23    Stop    Stop process
       SIGTSTP   18,20,24    Stop    Stop typed at tty
       SIGTTIN   21,21,26    Stop    tty input for background process
       SIGTTOU   22,22,27    Stop    tty output for background process

The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored. 

How to trap all the signals (except few..!!) ??
here is the example: 

#!/usr/bin/python
import signal

def sighandler(signum, frame):
 print "Caough signal :", signum

for x in dir(signal):
  if x.startswith("SIG"):
     try:
        signum = getattr(signal,x)
        signal.signal(signum,sighandler)
     except:
        print "Skipping %s"%x
   
while True:
      pass


Printing stack frames :

The frame argument is the stack frame also known as execution frame. It point to the frame that was interrupted by the signal. to print the stack trace you need to use 'traceback' module. 
this is very useful in multi-threaded program because any thread might be interrupted by a signals and signal is only received by the main program. 


#!/usr/bin/python
import signal,traceback

def sighandler(signum, frame):
 print "Caough signal :", signum
 traceback.print_stack(frame)

for sig in dir(signal):
  if sig.startswith("SIG"):
     try:
        signum = getattr(signal,sig)
        signal.signal(signum,sighandler)
     except:
        print "Skipping %s"%sig
   
while True:
      pass

Ignoring signals:

To ignore a signal, register SIG_IGN as the handler (no call back required). This will ignore the ctr+c signal raised from terminal.

#!/usr/bin/python
import signal

signal.signal(signal.SIGINT,signal.SIG_IGN)

while True:
 pass