Skip to content

concurrent.futures.wait() waits forever if given a cancelled future #92001

Open
@lordmauve

Description

@lordmauve

Bug report

concurrent.futures.wait() hangs if given a future that is already cancelled.

Steps to reproduce:

  1. Get a future that is cancellable (create lots of jobs such that the later ones cannot start yet and are therefore cancellable):
>>> import concurrent.futures
>>> pool = concurrent.futures.ThreadPoolExecutor(max_workers=1)
>>> import time
>>> for _ in range(1000): future = pool.submit(time.sleep, 1000)
  1. Cancel this future and note that it returns True meaning it has been cancelled.
>>> future.cancel()
True
  1. Now waiting on this future hangs:
>>> concurrent.futures.wait([future]) 

The expected behaviour, regardless of the value of return_when is that wait() treats cancelled futures as already completed. This is essentially how return_when=FIRST_COMPLETED and return_when=ALL_COMPLETED are documented to behave:

The function will return when any future finishes or is cancelled.

and

The function will return when all futures finish or are cancelled.

Treating a future that is cancelled prior to wait() as different to one that changes state to cancelled once waiting risks a race condition: it could change state after any possible check but before blocking. i.e. it needs to be level-triggered not edge-triggered. And indeed, it works this way for futures that are done, just not ones that are cancelled.

Your environment

  • CPython versions tested on: 3.9.7, 3.10.2
  • Operating system and architecture: Linux

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions