Sunday, August 26, 2012

Join() method in Python Threading


Python Docs for join():
Wait until the thread terminates. This blocks the calling thread until the thread whose join() method is called terminates – either normally or through an unhandled exception – or until the optional timeout occurs.

A nice explanation available at: http://www.cs.mtu.edu/~shene/NSF-3/e-Book/FUNDAMENTALS/thread-management.html

Imagine the following scenario. You are preparing for tomorrow's final examine and feel a little hungry. So, you give your younger brother ten bucks and ask him to buy a pizza for you. In this case, you are the main thread and your brother is a child thread. Once your order is given, both you and your brother are doing their job concurrently (i.e., studying and buying a pizza). Now, we have two cases to consider. First, your brother brings your pizza back and terminates while you are studying. In this case, you can stop studying and enjoy the pizza. Second, you finish your study early and sleep (i.e., your assigned job for today - study for tomorrow's final exam - is done) before the pizza is available. Of course, you cannot sleep; otherwise, you won't have a chance to eat the pizza. What you are going to do is to wait until your brother brings the pizza back. This is exactly the problem and solution we mentioned at the end of the previous section.

Thread join is designed to solve this problem. A thread can execute a thread join to wait until the other thread terminates. In our case, you - the main thread - should execute a thread join waiting for your brother - a child thread - to terminate. In general, thread join is for a parent to join with one of its child threads. Thread join has the following activities, assuming that a parent thread P wants to join with one of its child threads C.

When P executes a thread join in order to join with C, which is still running, P is suspended until C terminates. Once C terminates, P resumes.
When P executes a thread join and C has already terminated, P continues as if no such thread join has ever executed (i.e., join has no effect).
A parent thread may join with many child threads created by the parent. Or, a parent only join with some of its child threads, and ignore other child threads. In this case, those child threads that are ignored by the parent will be terminated when the parent terminates.

import threading
import time

threads = []
class myThreading(threading.Thread):
    def __init__(self,counter):
        threading.Thread.__init__(self)
        self.counter=counter
     
    def run(self):
        print "In :" + self.name
        self.someFun(self.counter)
        print "Out :" + self.name
 
    def someFun(self,counter):
        time.sleep(counter)

a=myThreading(5)
a.start()
b=myThreading(1)
b.start()

threads.append(a)
#threads.append(b)

for t in threads:
    t.join()
 
print "main"


The main thread will wait for "a" to finish before printing "main".

Threading in Python


By import threading :

acc. to Python Docs:
Threads can be created by passing a callable object to the constructor, or by overriding the run() method in a subclass.

1) overriding the run() method in a subclass

import threading
import time

class myThreading(threading.Thread):
    def __init__(self,counter):
        print "In init__"
        self.counter=counter
        threading.Thread.__init__(self)
   
    def run(self):
        print "in Run " + self.name
        tFunc(self.name,self.counter)
        #time.sleep(1)
   
    def pCount(self):
        print threading.activeCount()
        #print threading.enumerate()
       
def tFunc(name,counter):
    while counter :
        print "Name:" + name
        counter -= 1
       
tObj1=myThreading(2)
tObj1.start()


start() starts the thread activity. It arranges for the object’s run() method to be invoked in a separate thread of control.

start() will create a thread. run() function will be executed in tht thread
tObj1.run() will not create thread. It will simply execute run method of same class.
Or in other words tObj1.run() will just call run() function  in the current (calling) Thread.

2) passing a callable object to the constructor

import threading
import time

class myThreading(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self,target=tFunc,name='tName',args=(2,))

def tFunc(counter):
    while counter:
        print "Count :", counter
        counter -= 1
       
tObj1=myThreading()
tObj1.start()