This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Remove restriction against Semaphore having a negative value
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.4
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: amaury.forgeotdarc, ezio.melotti, neologix, pitrou, rhettinger, sbt
Priority: normal Keywords:

Created on 2013-03-07 08:57 by rhettinger, last changed 2022-04-11 14:57 by admin.

Files
File name Uploaded Description Edit
barrier.py rhettinger, 2013-03-07 08:57 Demonstrate a simple barrier using a semaphore with a negative value
Messages (12)
msg183642 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2013-03-07 08:57
I was working through the problem sets in The Little Book of Semaphores (http://www.greenteapress.com/semaphores/downey08semaphores.pdf) and ran into an issue because Python's threading.Semaphore has an unnecessary restriction against having negative values.

That precludes use cases such as simple barriers (i.e. wait on five signals before a wait is released).

Various descriptions of Semaphores allow their counts to be set to arbitrary integer values.  Here's one definition:

   1. When you create the semaphore, you can initialize its 
      value to any integer, but after that the only operations 
      you are allowed to perform are increment (increase by one) 
      and decrement (decrease by one). You cannot read the current
      value of the semaphore.
   2. When a thread decrements the semaphore, if the result is negative,
      the thread blocks itself and cannot continue until another 
      thread increments the semaphore.
   3. When a thread increments the semaphore, if there are other 
      threads waiting, one of the waiting threads gets unblocked.

The patch is simple, remove the guard in the initialization and change the value==0 test with value<=0 to trigger blocking.

A bit of demonstration code is attached.
msg183643 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2013-03-07 09:08
For reference, here is the Java API for a Semaphore ( http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html ):

Semaphore
---------
public Semaphore(int permits)

Creates a Semaphore with the given number of permits and nonfair fairness setting.

Parameters:

permits - the initial number of permits available. This value may be negative, in which case releases must occur before any acquires will be granted.
msg183647 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2013-03-07 09:38
>  3. When a thread increments the semaphore, if there are other 
>     threads waiting, one of the waiting threads gets unblocked.
Is a condition missing here? "if the resulting count is positive"

Since the use case is different from a regular Semaphore, I think it make sense to have a new Barrier class.  It's not obvious for me why I need (1-n) to wait for n completed tasks.
msg183649 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-03-07 10:07
We already have a Barrier class actually: http://docs.python.org/dev/library/threading.html#barrier-objects

As for accepting negative initialization values, it sounds like a reasonable request. One reason for rejecting would be if it makes writing a fast implementation harder. Also, multiprocessing.Semaphore should be kept compatible with threading.Semaphore.
msg183651 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-03-07 11:00
> As for accepting negative initialization values, it sounds like a reasonable request. One reason for rejecting would be if it makes writing a fast implementation harder. Also, multiprocessing.Semaphore should be kept compatible with threading.Semaphore.

Unfortunately, POSIX semaphore don't support negative initial value.
Multiprocessing semaphores are based on POSIX semaphores on Unix, and
one can imagine an alternate implementation of Semaphore based atop
POSIX semaphores.
msg183901 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2013-03-10 22:11
[Antoine]
> multiprocessing.Semaphore should be kept compatible 
> with threading.Semaphore.

I just looked at the C code implementing multiprocessing Semaphore.  Removing the negative count restriction there looks straight-forward.  I'll include it in the patch or will open a separate tracker item for it.

[Charles-François]
> POSIX semaphore don't support negative initial value.

It was an early design decision to go with the Java threading model rather than the POSIX model.  The Java API supports negative initial values -- the same Dijkstra's original P() and V().
msg184752 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-03-20 11:18
>> POSIX semaphore don't support negative initial value.
>
> It was an early design decision to go with the Java threading model rather than the POSIX model.  The Java API supports negative initial values -- the same Dijkstra's original P() and V().

Hum, yes, but my point was that multiprocessing semaphores are
implemented atop POSIX semaphores, which don't support negative
initial values.
Also, since the API doesn't allow negative values, it's possible that
an implementation uses the native POSIX semaphores, and this change
would break such implementations.

> I just looked at the C code implementing multiprocessing Semaphore.  Removing the negative count restriction there looks straight-forward.  I'll include it in the patch or will open a separate tracker item for it.

I'm not so sure about this, how would you do it?
msg184757 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-03-20 12:44
I also don't think "Java does it" is a good design justification anymore.
Python's threading model is the Python threading model, even though it
may have been inspired by Java at the start :-)
msg184759 - (view) Author: Ezio Melotti (ezio.melotti) * (Python committer) Date: 2013-03-20 12:51
You might want to rephrase the module docstring of Lib/threading.py then :)
msg184761 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-03-20 13:16
> You might want to rephrase the module docstring of Lib/threading.py
> then :)

I think I already suggested rephrasing it but apparently it was lost
somewhere.
msg184763 - (view) Author: Ezio Melotti (ezio.melotti) * (Python committer) Date: 2013-03-20 13:30
msg183614 in #12768?
msg184767 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-03-20 14:56
> msg183614 in #12768?

Exactly.
History
Date User Action Args
2022-04-11 14:57:42adminsetgithub: 61576
2013-03-20 14:56:05pitrousetmessages: + msg184767
2013-03-20 13:30:31ezio.melottisetmessages: + msg184763
2013-03-20 13:16:07pitrousetmessages: + msg184761
2013-03-20 12:51:33ezio.melottisetnosy: + ezio.melotti
messages: + msg184759
2013-03-20 12:44:24pitrousetmessages: + msg184757
title: Remove restriction against Semaphore having a negative value -> Remove restriction against Semaphore having a negative value
2013-03-20 11:18:45neologixsetmessages: + msg184752
2013-03-10 22:11:51rhettingersetmessages: + msg183901
2013-03-07 11:00:24neologixsetmessages: + msg183651
2013-03-07 10:07:13pitrousetnosy: + neologix, sbt
messages: + msg183649
2013-03-07 09:38:31amaury.forgeotdarcsetnosy: + amaury.forgeotdarc
messages: + msg183647
2013-03-07 09:08:14rhettingersetmessages: + msg183643
2013-03-07 08:58:15rhettingersetnosy: + pitrou
2013-03-07 08:57:52rhettingercreate