Curs 11
Curs 11
Curs 11
Course 11
THREADING AND SYNCHRONIZATION
Python threading support is achieved through two modules:
o _thread ➔ old methods, low-level methods
o threading ➔ new methods, based on a class model
Besides these a series of synchronization object that include locks, semaphores, events
are also available.
As thread module was renamed in python 3 to _thread. It is best to use threading if you
want a code that will run in the same way in Python 2 and Python 3.
THREADING AND SYNCHRONIZATION
To start a new thread use start_new_thread method from class thread. The method
receives a function that will be executed on the new thread and functions parameters.
Python 3.x
import _thread,time
Output
def MyPrint(sleepPeriod,name,count): Thread #1=>0
for i in range(0,count): Thread #3=>0
Thread #2=>0
print (name+"=>"+str(i)) Thread #1=>1
time.sleep(sleepPeriod) Thread #2=>1
Thread #1=>2
#main thread
_thread.start_new_thread (MyPrint, (1,"Thread #1", 3))
_thread.start_new_thread (MyPrint, (2,"Thread #2", 2))
_thread.start_new_thread (MyPrint, (3,"Thread #3", 1))
time.sleep(10)
THREADING AND SYNCHRONIZATION
In case of objects that are not thread-safe a lock can be used. Output 1 Output 2
Python 3.x Thread #1=>0 Thread #3=>0
Thread #3=>0 Thread #1=>0
import _thread,time Thread #2=>0 Thread #2=>0
lock = _thread.allocate_lock() Thread #1=>1 Thread #1=>1
def MyPrint(sleepPeriod,name,count): Thread #1=>2 Thread #2=>1
Thread #2=>1 Thread #1=>2
global lock Thread #3=>1 Thread #3=>1
for i in range(0,count): Thread #2=>2 Thread #2=>2
lock.acquire() Thread #3=>2 Thread #3=>2
print (name+"=>"+str(i)) Thread #3=>3 Thread #3=>3
lock.release()
time.sleep(sleepPeriod)
_thread.start_new_thread (MyPrint, (1,"Thread #1", 3))
_thread.start_new_thread (MyPrint, (2,"Thread #2", 3))
_thread.start_new_thread (MyPrint, (3,"Thread #3", 4))
time.sleep(10)
THREADING AND SYNCHRONIZATION
Locks can also be used with with statement (in this case the acquire and release are
called in __enter __ and __exit__ code ) Output 1 Output 2
Python 3.x Thread #1=>0 Thread #2=>0
import _thread,time Thread #3=>0 Thread #1=>0
lock = _thread.allocate_lock() Thread #2=>0 Thread #3=>0
Thread #1=>1 Thread #1=>1
def MyPrint(sleepPeriod,name,count): Thread #1=>2 Thread #2=>1
global lock Thread #2=>1 Thread #1=>2
for i in range(0,count): Thread #3=>1 Thread #3=>1
Thread #2=>2 Thread #2=>2
with lock: Thread #3=>2 Thread #3=>2
print (name+"=>"+str(i)) Thread #3=>3 Thread #3=>3
time.sleep(sleepPeriod)
_thread.start_new_thread (MyPrint, (1,"Thread #1", 3))
_thread.start_new_thread (MyPrint, (2,"Thread #2", 3))
_thread.start_new_thread (MyPrint, (3,"Thread #3", 4))
time.sleep(10)
THREADING AND SYNCHRONIZATION
Locks can also be used to wait for a thread to finish.
Python 3.x
import _thread,time
lock = _thread.allocate_lock()
lock.acquire() Output
def MyPrint(sleepPeriod,name,count): Waiting for a thread to finish ...
Thread #1=>0
global lock Thread #1=>1
for i in range(0,count): Thread #1=>2
print (name+"=>"+str(i)) Thread finished
time.sleep(sleepPeriod)
lock.release()
_thread.start_new_thread (MyPrint, (1,"Thread #1", 3))
print ("Waiting for a thread to finish ...")
lock.acquire()
print ("Thread finished")
THREADING AND SYNCHRONIZATION
Locks can also be used to wait for a thread to finish.
Python 3.x
import _thread,time
lock = _thread.allocate_lock() Step 1:
lock.acquire() lock variable is acquired
def MyPrint(sleepPeriod,name,count): before any thread is started.
global lock
for i in range(0,count):
print (name+"=>"+str(i))
time.sleep(sleepPeriod)
lock.release()
_thread.start_new_thread (MyPrint, (1,"Thread #1", 3))
print ("Waiting for a thread to finish ...")
lock.acquire()
print ("Thread finished")
THREADING AND SYNCHRONIZATION
Locks can also be used to wait for a thread to finish.
Python 3.x
import _thread,time Step 2:
lock = _thread.allocate_lock() Main thread tries to acquire
lock.acquire() again the lock variable. As
def MyPrint(sleepPeriod,name,count): this variable was already
global lock acquired, the main thread
for i in range(0,count): will wait until lock variable is
print (name+"=>"+str(i)) released.
time.sleep(sleepPeriod)
lock.release()
_thread.start_new_thread (MyPrint, (1,"Thread #1", 3))
print ("Waiting for a thread to finish ...")
lock.acquire()
print ("Thread finished")
THREADING AND SYNCHRONIZATION
Locks can also be used to wait for a thread to finish.
Python 3.x
import _thread,time Step 3:
lock = _thread.allocate_lock() When “Thread #1” is
lock.acquire() finished the lock variable is
def MyPrint(sleepPeriod,name,count): released. At that point the
global lock call to lock.acquire from the
for i in range(0,count): main thread will be executed
print (name+"=>"+str(i)) and the script will continue.
time.sleep(sleepPeriod)
lock.release()
_thread.start_new_thread (MyPrint, (1,"Thread #1", 3))
print ("Waiting for a thread to finish ...")
lock.acquire()
print ("Thread finished")
THREADING AND SYNCHRONIZATION
Exceptions not caught in a different thread than the main thread will not stop the
program.
Python 3.x
import _thread,time
def MyPrint(sleepPeriod,name,count):
global lock
for i in range(-count,count):
print (name+"=>"+str(10/i))
time.sleep(sleepPeriod)
_thread.start_new_thread (MyPrint, (1,"Thread #1", 3))
for i in range(0,10):
print ("Main thread : "+str(i))
time.sleep(1)
THREADING AND SYNCHRONIZATION
Exceptions not caught in a different thread than the main thread will not stop the
program.
Output
Python 3.x Main thread : 0
import _thread,time
Thread #1=>-3.3333333333333335
Thread #1=>-5.0
def MyPrint(sleepPeriod,name,count):
Main thread : 1
global lock
Thread #1=>-10.0
for Main
i inthread
range(-count,count):
: 2
Unhandled
printexception in thread started by <function MyPrint at 0x019C3810>
(name+"=>"+str(10/i))
Traceback (most recent call last):
time.sleep(sleepPeriod)
Main thread : 3
_thread.start_new_thread (MyPrint, (1,"Thread #1", 3))
File "E:\Documente\Facultate\Python\2019-2020\p.py", line 5, in MyPrint
for i in range(0,10):
print (name+"=>"+str(10/i))
ZeroDivisionError:
print ("Main threaddivision by zero
: "+str(i))
Main thread : 4
time.sleep(1)
Main thread : 5
Main thread : 6
Main thread : 7
Main thread : 8
Main thread : 9
THREADING AND SYNCHRONIZATION
Threading module provides high level functions for thread workers and synchronization.
It also provides a class Thread that can be used to derive thread based objects. When
deriving from a Thread class two methods are usually implemented:
o run() ➔ code that will be executed when the thread starts
o __init__ ➔ thread constructor (it is important to call __init__ from thee base class before doing
anything with the thread
def WaitSomeSeconds(seconds):
time.sleep(seconds)
t = Mythread(3)
t.start()
print("Wait for the thread to complete ...")
t.join()
SYNCHRONIZATION
The following synchronization object are available in threading module:
o lock
o rlock (reentrant lock)
o Condition objects
o Semaphore
o Event
o Timer
o Barrier
SYNCHRONIZATION (LOCK)
Allows synchronized access to a resource.
Lock objects have two functions:
1. Python 3: Lock.acquire(blocking=True, timeout=-1) (timeout means how many seconds
the Lock has to wait until it is acquired.
def WorkerThread(b,id):
b_id = b.wait()
print("#"+str(id)+" pass the barier => "+str(b_id))
time.sleep(2)
print("#"+str(id)+" exit")
t = []
for i in range(0,10):
t += [threading.Thread(target=WorkerThread, args=(i,))]
for _th in t: _th.start ()
for _th in t: _th.join ()
SYNCHRONIZATION (BARRIER) Output
#1 pass the barier => 1
Python 3.x #0 pass the barier => 0
#3 pass the barier => 1
import threading,time #2 pass the barier => 0
b = threading.Barrier(2) #5 pass the barier => 1
#4 pass the barier => 0
#7 pass the barier => 1
def WorkerThread(b,id): #6 pass the barier => 0
b_id = b.wait() #9 pass the barier => 1
print("#"+str(id)+" pass the barier => "+str(b_id))
#8 pass the barier => 0
time.sleep(2) #1 exit
#3 exit
print("#"+str(id)+" exit") #2 exit
#0 exit
t = [] #6 exit
#4 exit
for i in range(0,10): #9 exit
t += [threading.Thread(target=WorkerThread, args=(i,))]
#5 exit
for _th in t: _th.start () #7 exit
for _th in t: _th.join () #8 exit
SYNCHRONIZATION (BARRIER) Output
#1 pass the barier => 1
Python 3.x #0 pass the barier => 0
#3 pass the barier => 1
import threading,time #2 pass the barier => 0
b = threading.Barrier(2) #5 pass the barier => 1
Each barrier waits for 2 #4 pass the barier => 0
thread. The b_id #7 pass the barier => 1
def WorkerThread(b,id):
parameter indicates the #6 pass the barier => 0
b_id = b.wait() #9 pass the barier => 1
id of a thread inside a
print("#"+str(id)+" pass the barier => "+str(b_id))#8 pass the barier => 0
barrier. The call to wait #1 exit
time.sleep(2)
exits only when all #3 exit
print("#"+str(id)+" exit")
threads that need to #2 exit
#0 exit
pass the barrier are
t = [] #6 exit
present (in this case #4 exit
for i in range(0,10):
from 2 to 2 threads). #9 exit
t += [threading.Thread(target=WorkerThread, args=(i,))]
#5 exit
for _th in t: _th.start () #7 exit
for _th in t: _th.join () #8 exit
SYNCHRONIZATION (BARRIER)
Python 3.x
import threading,time
b = threading.Barrier(3)