mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
gh-105829: Fix concurrent.futures.ProcessPoolExecutor deadlock (#108513)
This fixes issue #105829, https://github.com/python/cpython/issues/105829 Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Antoine Pitrou <antoine@python.org> Co-authored-by: Chris Withers <chris@withers.org> Co-authored-by: Thomas Moreau <thomas.moreau.2010@gmail.com>
This commit is contained in:
parent
e94a2232ea
commit
405b06375a
3 changed files with 87 additions and 4 deletions
|
@ -71,6 +71,11 @@ class _ThreadWakeup:
|
|||
self._reader, self._writer = mp.Pipe(duplex=False)
|
||||
|
||||
def close(self):
|
||||
# Please note that we do not take the shutdown lock when
|
||||
# calling clear() (to avoid deadlocking) so this method can
|
||||
# only be called safely from the same thread as all calls to
|
||||
# clear() even if you hold the shutdown lock. Otherwise we
|
||||
# might try to read from the closed pipe.
|
||||
if not self._closed:
|
||||
self._closed = True
|
||||
self._writer.close()
|
||||
|
@ -426,8 +431,12 @@ class _ExecutorManagerThread(threading.Thread):
|
|||
elif wakeup_reader in ready:
|
||||
is_broken = False
|
||||
|
||||
with self.shutdown_lock:
|
||||
self.thread_wakeup.clear()
|
||||
# No need to hold the _shutdown_lock here because:
|
||||
# 1. we're the only thread to use the wakeup reader
|
||||
# 2. we're also the only thread to call thread_wakeup.close()
|
||||
# 3. we want to avoid a possible deadlock when both reader and writer
|
||||
# would block (gh-105829)
|
||||
self.thread_wakeup.clear()
|
||||
|
||||
return result_item, is_broken, cause
|
||||
|
||||
|
@ -717,7 +726,10 @@ class ProcessPoolExecutor(_base.Executor):
|
|||
# as it could result in a deadlock if a worker process dies with the
|
||||
# _result_queue write lock still acquired.
|
||||
#
|
||||
# _shutdown_lock must be locked to access _ThreadWakeup.
|
||||
# _shutdown_lock must be locked to access _ThreadWakeup.close() and
|
||||
# .wakeup(). Care must also be taken to not call clear or close from
|
||||
# more than one thread since _ThreadWakeup.clear() is not protected by
|
||||
# the _shutdown_lock
|
||||
self._executor_manager_thread_wakeup = _ThreadWakeup()
|
||||
|
||||
# Create communication channels for the executor
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue