Skip to content

Commit 7634e1c

Browse files
author
Tim Peters
committed
Issue 19158: a rare race in BoundedSemaphore could allow .release() too often.
1 parent ee82d0b commit 7634e1c

File tree

2 files changed

+23
-3
lines changed

2 files changed

+23
-3
lines changed

Lib/test/test_threading.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,24 @@ def test_is_alive_after_fork(self):
468468
self.assertEqual(0, status)
469469

470470

471+
def test_BoundedSemaphore_limit(self):
472+
# BoundedSemaphore should raise ValueError if released too often.
473+
for limit in range(1, 10):
474+
bs = threading.BoundedSemaphore(limit)
475+
threads = [threading.Thread(target=bs.acquire)
476+
for _ in range(limit)]
477+
for t in threads:
478+
t.start()
479+
for t in threads:
480+
t.join()
481+
threads = [threading.Thread(target=bs.release)
482+
for _ in range(limit)]
483+
for t in threads:
484+
t.start()
485+
for t in threads:
486+
t.join()
487+
self.assertRaises(ValueError, bs.release)
488+
471489
class ThreadJoinOnShutdown(BaseTestCase):
472490

473491
# Between fork() and exec(), only async-safe functions are allowed (issues

Lib/threading.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,11 @@ def __init__(self, value=1):
283283
self._initial_value = value
284284

285285
def release(self):
286-
if self._value >= self._initial_value:
287-
raise ValueError("Semaphore released too many times")
288-
return Semaphore.release(self)
286+
with self._cond:
287+
if self._value >= self._initial_value:
288+
raise ValueError("Semaphore released too many times")
289+
self._value += 1
290+
self._cond.notify()
289291

290292

291293
class Event:

0 commit comments

Comments
 (0)