Skip to content

Commit a8cae40

Browse files
authored
gh-107219: Fix concurrent.futures terminate_broken() (#108974)
Fix a race condition in _ExecutorManagerThread.terminate_broken(): ignore the InvalidStateError on future.set_exception(). It can happen if the future is cancelled before the caller. Moreover, test_crash_big_data() now waits explicitly until the executor completes.
1 parent b298b39 commit a8cae40

File tree

2 files changed

+10
-1
lines changed

2 files changed

+10
-1
lines changed

Lib/concurrent/futures/process.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,14 @@ def terminate_broken(self, cause):
489489

490490
# Mark pending tasks as failed.
491491
for work_id, work_item in self.pending_work_items.items():
492-
work_item.future.set_exception(bpe)
492+
try:
493+
work_item.future.set_exception(bpe)
494+
except _base.InvalidStateError as exc:
495+
# set_exception() fails if the future is cancelled: ignore it.
496+
# Trying to check if the future is cancelled before calling
497+
# set_exception() would leave a race condition if the future is
498+
# cancelled betwen the check and set_exception().
499+
pass
493500
# Delete references to object. See issue16284
494501
del work_item
495502
self.pending_work_items.clear()

Lib/test/test_concurrent_futures/test_deadlock.py

+2
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ def test_crash_big_data(self):
239239
with self.assertRaises(BrokenProcessPool):
240240
list(executor.map(_crash_with_data, [data] * 10))
241241

242+
executor.shutdown(wait=True)
243+
242244

243245
create_executor_tests(globals(), ExecutorDeadlockTest,
244246
executor_mixins=(ProcessPoolForkMixin,

0 commit comments

Comments
 (0)