pythonpython-3.xmultithreadingthread-safetyrace-condition

Can a multi-threaded Python app change the CWD?


Would the assert statement in this code raise an error under any Python 3.11+ interpreter?

Can the current working directory be changed by another module without this code using any async features?

import os
cwd1 = os.getcwd()
# can another module change the CWD here?
cwd2 = os.getcwd()
assert cwd1 == cwd2

I need to know if the CWD would stay the same in all situations with code like the example, or if I have to check, as rare as it may be, due to a race condition.

In other words, is that code thread-safe?


Solution

  • The working directory is owned by the process that starts the threads, so yes a thread can change the cwd and it will effect all threads in the process. For example this fails with an assertion error for me:

    import threading
    import time
    import os
    
    
    def test2():
        time.sleep(2)
        os.chdir('../')
    
    
    def test1():
        cwd1 = os.getcwd()
        time.sleep(3)
        cwd2 = os.getcwd()
        assert cwd1 == cwd2
    
    
    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    

    Edit based on comments

    Using these functions you can see it's not deterministic — it sometimes fails, sometimes doesn't. But, importantly, it sometimes fails:

    def test2():
        os.chdir('../')
    
    
    def test1():
        cwd1 = os.getcwd()
        cwd2 = os.getcwd()
        try:
            assert cwd1 == cwd2
        except AssertionError:
            print("failed", cwd1, cwd2)
            return
    

    In fact, it will often even fail with:

     assert os.getcwd() == os.getcwd()
    

    Demonstrating that your thread can be suspended even within a single line.