threading.BoundedSemaphore(value=1)
You can use
bounded semaphore to make sure you never call release() too many times. A
bounded semaphore checks to make sure its current value doesn’t exceed its initial
value. If it does, ValueError is raised.
For example,
following program implemented using simple semaphore, allows maximum three
threads at a time into critical section.
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) #Critical section sem.acquire() print("Started execution : ", name) threads.append(name) time.sleep(1) print("Finished Execution : ", name) print(threads) sem.release() 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'] Started execution : thread_3 Finished Execution : thread_1 ['thread_1', 'thread_2', 'thread_3'] Finished Execution : thread_2 ['thread_2', 'thread_3'] Started execution : thread_4 Started execution : thread_5 Finished Execution : thread_3 ['thread_3', 'thread_4', 'thread_5'] Finished Execution : thread_4 ['thread_4', 'thread_5'] Started execution : thread_6 Finished Execution : thread_5 ['thread_5', 'thread_6'] Started execution : thread_8 Started execution : thread_7 Finished Execution : thread_6 ['thread_6', 'thread_8', 'thread_7'] Finished Execution : thread_8 Finished Execution : thread_7 ['thread_8', 'thread_7'] Started execution : thread_9 ['thread_8', 'thread_7'] Finished Execution : thread_9 ['thread_9']
Observe the
output, at any time maximum 3 thread can able to run critical section of
process method.
Suppose, if
you call release method more than acquire methods, then your output collapse.
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) #Critical section sem.acquire() print("Started execution : ", name) threads.append(name) time.sleep(1) print("Finished Execution : ", name) print(threads) sem.release() 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() semaphore.release()
I just added
‘semaphore.release()’ at the end of
file.
$ 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 Started execution : thread_3 Waiting to start execution : thread_4 Started execution : thread_4 Waiting to start execution : thread_5 Started execution : thread_5 Waiting to start execution : thread_6 Started execution : thread_6 Waiting to start execution : thread_7 Started execution : thread_7 Waiting to start execution : thread_8 Started execution : thread_8 Waiting to start execution : thread_9 Started execution : thread_9 Finished Execution : thread_0 ['thread_0', 'thread_1', 'thread_2', 'thread_3', 'thread_4', 'thread_5', 'thread_6', 'thread_7', 'thread_8', 'thread_9'] Finished Execution : thread_3 Finished Execution : thread_2 ['thread_1', 'thread_2', 'thread_3', 'thread_4', 'thread_5', 'thread_6', 'thread_7', 'thread_8', 'thread_9'] Finished Execution : thread_4 Finished Execution : thread_1 ['thread_1', 'thread_2', 'thread_3', 'thread_4', 'thread_5', 'thread_6', 'thread_7', 'thread_8', 'thread_9'] ['thread_1', 'thread_2', 'thread_4', 'thread_5', 'thread_6', 'thread_7', 'thread_8', 'thread_9'] ['thread_1', 'thread_2', 'thread_4', 'thread_5', 'thread_6', 'thread_7', 'thread_8', 'thread_9'] Finished Execution : thread_6 Finished Execution : thread_5 ['thread_5', 'thread_6', 'thread_7', 'thread_8', 'thread_9'] Finished Execution : thread_7 ['thread_5', 'thread_6', 'thread_7', 'thread_8', 'thread_9'] ['thread_5', 'thread_7', 'thread_8', 'thread_9'] Finished Execution : thread_8 ['thread_8', 'thread_9'] Finished Execution : thread_9 ['thread_9']
Calling
release function more times causes more threads entered into critical section
simultaneously.
By using BoundedSemaphore,
we can solve these problems. A bounded semaphore checks to make sure its current
value doesn’t exceed its initial value. If it does, ValueError is raised.
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) #Critical section sem.acquire() print("Started execution : ", name) threads.append(name) time.sleep(1) print("Finished Execution : ", name) print(threads) sem.release() threads.remove(name) semaphore=threading.BoundedSemaphore(value=3) for i in range(10): t = threading.Thread(target=process, name='thread_'+str(i), args=(semaphore,)) t.start() semaphore.release()
$ python3 SemaphoreEx.py Waiting to start execution : thread_0 Started execution : thread_0 Waiting to start execution : thread_1 Started execution : thread_1 Traceback (most recent call last): File "SemaphoreEx.py", line 27, in <module> semaphore.release() File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 480, in release raise ValueError("Semaphore released too many times") ValueError: Semaphore released too many times Finished Execution : thread_0 ['thread_0', 'thread_1'] Finished Execution : thread_1 ['thread_1'] Exception in thread thread_1: Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 923, in _bootstrap_inner self.run() File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 871, in run self._target(*self._args, **self._kwargs) File "SemaphoreEx.py", line 19, in process sem.release() File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 480, in release raise ValueError("Semaphore released too many times") ValueError: Semaphore released too many times
No comments:
Post a Comment