0

Please see the below code snippet, which fails to get past the first run locally with Python 3.10.

When I try to join all the threads within the built-in all function, always one of the threads is still alive.

What is the issue here, why is a race condition happening?

import time
from threading import Thread

def expose_race_condition(run_index: int) -> None:
    threads: list[Thread] = [
        Thread(target=time.sleep, args=(1,)) for _ in range(10)
    ]
    for thread in threads:
        thread.start()

    # RACE CONDITION IS HERE
    assert not all(thread.join() for thread in threads)
    for thread_index, thread in enumerate(threads):
        # Uncommenting the below line defeats the race condition
        # assert not thread.join()
        assert (
            not thread.is_alive()
        ), f"Worker {thread_index} in run {run_index} was still alive."
    print(f"Completed run {run_index}")

if __name__ == "__main__":
    for i in range(10_000):
        expose_race_condition(i)
Intrastellar Explorer
  • 3,005
  • 9
  • 52
  • 119

1 Answers1

4

Sorry, I don't understand what you're trying to do. This line, for example:

   assert not all(thread.join() for thread in threads)

just doesn't make sense. .join() always returns None, so it's the same as

   assert not all(None for thread in threads)

except that it has the side effect of joining threads. all() short-circuits the first time it sees a False value, which None is, so only the first .join() is actually called. all(...) returns False, so not all(...) returns True, so the assert succeeds. It's like:

    threads[0].join()
    assert True

Short course: any code paying any attention to the value thread.join() returns is probably flat-out broken, because None is the only value it will ever see.

Tim Peters
  • 67,464
  • 13
  • 126
  • 132
  • 1
    Wow... yes this is embarrassing. Thank you @TimPeters for pointing out what is a rookie mistake, for some reason I thought `Thread.join` returned a `bool`. And the `all`'s short-circuiting behavior... that makes sense. Thank you again! – Intrastellar Explorer Apr 23 '22 at 01:16