Search code examples
pythonmultithreadingclassasynchronousmember

Python member variables of different data types not getting updated in different thread with same priority


Consider this sample code:

class Test:
    def __init__(self) -> None:
        self.bool = False
        self.string = ""
        thread = Thread(target = self.target)
        thread.start()

    def target(self):
        while True:
            if self.bool:
                print("Bool changed")
                break

            if self.string != "":
                print("String changed")
                break
    
    def changeBool(self):
        self.bool = True
    
    def changeString(self):
        self.string = "sample"

var = Test()
var.changeString()
var.changeBool()

Here, I have two member variables in a class: a boolean and a string. In the constructor, I start a new thread to run a function which basically tells me which of the two variables gets modified inside the thread first.

When I run this program, even though I am calling changeString() first, the output is always "Bool changed". This means that the boolean is getting updated inside the thread faster than the string. Why does this happen? And how can I ensure that self.bool gets updated inside the thread immediately after it is modified in the main thread?


Solution

  • I tried implementing a thread-safe queue as per @Wombatz's suggestion, and that worked. Here's the modified code:

    class Test:
        def __init__(self) -> None:
            self.queue = queue.Queue()
            thread = Thread(target = self.target)
            thread.start()
    
        def target(self):
            while True:
                try:
                    message = self.queue.get_nowait()
                    if message[0] == "bool":
                        print(f"Bool changed to {message[1]}")
                        break
    
                    if message[0] == "string":
                        print(f"String changed to {message[1]}")
                        break
                except queue.Empty: pass
        
        def changeBool(self):
            self.queue.put(("bool", True))
        
        def changeString(self):
            self.queue.put(("string", "hello"))
    
    var = Test()
    var.changeBool()
    var.changeString()