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.
No comments:
Post a Comment