How is multiprocessing.BoundedSemaphore(3) different from multiprocessing.Sempahore(3)?
I was hoping that multiprocessing.BoundedSemaphore(3) would never allow its internal counter value to exceed 3.
From this I concluded, that even if my process that acquires this semaphore ends up erroneously releasing the semaphore more than one time (say acquiring it once but releasing it five times), it would not allow more than 3 processes to acquire the semaphore at any point of time. However, this conclusion of mine seems to be incorrect.
Here is my Python sample code in a file named multi.py.
#!/usr/bin/env python
import multiprocessing
import time
def f(i, sem):
print 'f(%d) acquiring ...' % i
sem.acquire()
print 'f(%d) acquired' % i
time.sleep(i + 1)
print 'f(%d) releasing ...' % i
sem.release()
sem.release() # Extra release on purpose
sem.release() # Extra release on purpose
sem.release() # Extra release on purpose
sem.release() # Extra release on purpose
print 'f(%d) released' % i
processes = []
sem = multiprocessing.BoundedSemaphore(3)
for i in range(10):
p = multiprocessing.Process(target=f, args=(i, sem))
p.start()
processes.append(p)
for p in processes:
p.join()
print 'Done'
Here is the output on my macOS Sierra 10.12.5 with Python 2.7.13. The blank lines between the output below have been inserted by me manually to indicate pauses between outputs.
$ ./multi.py [56/1853]
f(0) acquiring ...
f(0) acquired
f(1) acquiring ...
f(1) acquired
f(2) acquiring ...
f(2) acquired
f(3) acquiring ...
f(4) acquiring ...
f(5) acquiring ...
f(6) acquiring ...
f(7) acquiring ...
f(8) acquiring ...
f(9) acquiring ...
f(0) releasing ...
f(0) released
f(3) acquired
f(5) acquired
f(4) acquired
f(6) acquired
f(7) acquired
f(1) releasing ...
f(1) released
f(9) acquired
f(8) acquired
f(2) releasing ...
f(2) released
f(3) releasing ...
f(3) released
f(4) releasing ...
f(4) released
f(5) releasing ...
f(5) released
f(6) releasing ...
f(6) released
f(7) releasing ...
f(7) released
f(8) releasing ...
f(8) released
f(9) releasing ...
f(9) released
Done
The above output shows that f(0), f(1) and f(2) acquire the bounded-semaphore and the remaining processes block while trying to acquire indicating that the internal counter of the bounded-semaphore is now down to 0.
Then f(0) release the bounded-semaphore 5 times. After this, I was expecting the internal counter of the bounded-semaphore to be 3 (because it is bounded), so 3 more processes should be able to acquire the bounded-semaphore now. But from the output it looks like the internal-counter of the bounded-semaphore has increased to 5 because 5 processes acquire the bounded-semaphore. The 5 processes that acquire the bounded-semaphore are f(3), f(5), f(4), f(7) and f(7).
If it is possible for the internal counter of a multiprocessing.BoundedSemaphore object to exceed the initial value, then how is it different from multiprocessing.Semaphore?