Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why are changes made to a shared variable by one thread in Python not visible to other threads?

I’m trying to use the same variable in multiple threads, but the variable’s value isn’t being updated consistently across threads. For instance, when Thread 1 updates the variable to 1, Thread 2 doesn’t recognize this change and sees the old value instead.

Here’s a simple code example illustrating the problem. When the user presses the ‘a’ key, the variable ‘QUERY’ should update and display as follows:

  1. Query1: a
  2. Query: a

But, the actual output I’m getting is only:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  1. Query1: a

Can you help me understand why this is happening and how to fix it?

import getch
import threading

QUERY = ""
EXIT_THREAD = False
def input_thread():
    global EXIT_THREAD
    last_query = ""
    while not EXIT_THREAD:
        if last_query != QUERY:
            last_query = QUERY
            print(f"Query: {QUERY}")

thread = threading.Thread(target=input_thread)
thread.start()
while True:
    char = getch.getch()
    if char == "\n":
        break
    elif char == "\x7f":
        QUERY = QUERY[:-1]
    else:
        QUERY += char
    print(f"Query1: {QUERY}")
# kill input thread
EXIT_THREAD = True
thread.join()

>Solution :

The problem is that the getch module is poorly coded. It doesn’t release the GIL when it blocks waiting for input, so your other thread isn’t allowed to run. Synchronizing with locks doesn’t help much; the GIL is already protecting access to QUERY. The problem is that after each change to QUERY, you go back to getch, only handing off the GIL irregularly, and while blocked, both threads are blocked.

The proper solution would be for the getch module to release the GIL internally before making a blocking call, but failing that, you can give the other thread some time to run by intentionally blocking in a GIL-releasing manner just before each getch call, importing the time module, and adding a line here:

while True:
    time.sleep(0.001)  # Explicitly releases GIL for a millisecond
    char = getch.getch()

That gets the behavior you expect, and while technically subject to race conditions if other threads are involved, for just two threads like this it’s pretty reliable.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading