Sunday 20 December 2015

Python: Semaphores

Semaphore is used to restrict access to resources in multi threaded environment. There are two variants of semaphores.
a.   Binary semaphores
b.   Counting semaphores

Binary Semaphore
Binary semaphores represent two states (locked, unlocked). In a multi-threaded environment, resources are shared between threads. A resource is locked by a thread before using and released (unlocked) after using. If any thread wants to access a resource, which is locked, then this thread goes to blocking state.

Counting Semaphore
Counting semaphore represent more than one resource. If counting semaphore has maximum value X, means at max X threads can access the shared resource simultaneously. The counter is decremented when the semaphore is acquired, and incremented when the semaphore is released. If the counter reaches zero when acquired, the acquiring thread will block.

threading.Semaphore(value=1)
threading module provides Semaphore class to create a semaphore. ‘value’ represents the initial value for the counter, it defaults to 1. Whenever you call acquire method, counter is decremented by 1. Whenever you call release method, counter is incremented by 1. The acquire() method blocks if necessary until it can return without making the counter negative.

Method
Description
acquire(blocking=True, timeout=None)
Acquire a semaphore. If internal counter is greater than zero, then counter is decremented by 1. If counter is zero, then thread will be blocked, until some other thread calls the release method.

When invoked with blocking set to false, do not block.

When invoked with a timeout other than None, it will block for at most timeout seconds. If acquire does not complete successfully in that interval, return false. Return true otherwise.
release()
Release the semaphore and increment the internal counter by one. Wake up a thread that is waiting.
  

SemaphoreEx.py
import threading
import time

global threads
threads=[]

def process(sem):
 global threads
 name = threading.current_thread().getName()
 print("Waiting to start execution : ", name)
 with sem:
  print("Started execution : ", name)
  threads.append(name)
  time.sleep(1)
  print("Finished Execution : ", name)
 print(threads)
 threads.remove(name)

semaphore=threading.Semaphore(value=3)
for i in range(10):
 t = threading.Thread(target=process, name='thread_'+str(i), args=(semaphore,))
 t.start()

$ python3 SemaphoreEx.py 
Waiting to start execution :  thread_0
Started execution :  thread_0
Waiting to start execution :  thread_1
Started execution :  thread_1
Waiting to start execution :  thread_2
Started execution :  thread_2
Waiting to start execution :  thread_3
Waiting to start execution :  thread_4
Waiting to start execution :  thread_5
Waiting to start execution :  thread_6
Waiting to start execution :  thread_7
Waiting to start execution :  thread_8
Waiting to start execution :  thread_9
Finished Execution :  thread_0
['thread_0', 'thread_1', 'thread_2']
Finished Execution :  thread_1
['thread_1', 'thread_2']
Started execution :  thread_4
Started execution :  thread_3
Finished Execution :  thread_2
['thread_2', 'thread_4', 'thread_3']
Started execution :  thread_5
Finished Execution :  thread_4
['thread_4', 'thread_3', 'thread_5']
Finished Execution :  thread_3
['thread_3', 'thread_5']
Started execution :  thread_6
Started execution :  thread_7
Finished Execution :  thread_5
['thread_5', 'thread_6', 'thread_7']
Started execution :  thread_8
Finished Execution :  thread_6
['thread_6', 'thread_7', 'thread_8']
Started execution :  thread_9
Finished Execution :  thread_7
Finished Execution :  thread_8
['thread_7', 'thread_8', 'thread_9']
['thread_7', 'thread_8', 'thread_9']
Finished Execution :  thread_9
['thread_9']


Observe the output, at any time maximum 3 threads can able to run critical section of process method.





Previous                                                 Next                                                 Home

No comments:

Post a Comment