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

Async set/get variable in class will not work

I have async code that works as follows:

RUNNING=False

def is_running():
    global RUNNING
    return RUNNING

def my_stop_func():
    global RUNNING
    RUNNING = False


def start_threads():
    # code here that starts a number of threads
    # one of them can stop this service and calls my_stop_func()
    global RUNNING
    RUNNING = True

def join_threads():
    # Code that joins all created threads
    pass

def main():
    # init code etc...
    start_threads()

    while is_running():
        pass
    join_threads()

However doing the very small change below will not work.

class Hello:
    def __init__(self):
        self.running = False
HI = None

def is_running():
    global HI
    return HI.running

def my_stop_func():
    global HI
    HI.running = False


def start_threads():
    # code here that starts a number of threads
    # one of them can stop this service and calls my_stop_func()
    global HI
    HI = Hello()
    HI.running = True

Of course I’m doing it wrong, but I just haven’t found a solution that works even if I add async keywords with locks etc.
Any hints?

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

>Solution :

The problem you’re facing appears more to be logical error, rather than an issue with threading or async programming – in your original code you’re using variable RUNNING, that way you’re able to control the state of the threads, and now, in the class-based approach you’ve correctly encapsulated the state within an instance of the Hello class (HI), but there’s inconsistency in your my_stop_func function/method; In your original code, you set RUNNING = false which is indicator that thread should stop, and then in the class based approach you mistakenly set HI.running = True in my_stop_func, where it applies that the threads should keep running.

class Hello:
    def __init__(self):
        self.running = False

HI = None

def is_running():
    global HI
    return HI.running

def my_stop_func():
    global HI
    HI.running = False  # Corrected from True to False

def start_threads():
    # code here that starts a number of threads
    # one of them can stop this service and calls my_stop_func()
    global HI
    HI = Hello()
    HI.running = True

def main():
    # init code etc...
    start_threads()

    while is_running():
        pass  # Implement your thread monitoring or other logic here

As for async and locks, in case your threads are accessing shared resources or need to be synced, then using locks might be needed, but from provided code I suspect main concern is just to control the running state of the threads; therefore if you’re facing race conditions or other concurrency issues, you might need to implement locking mechanisms or use other sync primitives.

UPDATE 1:
As OP stated that issue with my_stop_func was just a typo and the rest of his code is class-based approach is as intended, there could be potential issues:

  1. Initialization of HI: You have to ensure that HI is initialized before any thread actually try to access its running attribute, that’s the most common issue if threads start running before HI is set to an instance of Hello;
  2. There could be potential problem with threading and object visibility, where in these kind of environments, changes that are made to an object in one thread might not be visible immediately to other threads, but again, because of GIL it’s less likely, but still should be considered.
  3. Race conditions: in case where multiple threads are doing R/W operation to HI.running without sync, you might run into race conditions -> solving these would be by using threading locks.
  4. The code that OP showed is using standard threading, not async programming, the async keyword and locks are more relevant in an asyncio-based programming, so in case you want to do this you can introduce a lock in the Hello class, then sync access to the running variable.
import threading

class Hello:
    def __init__(self):
        self.running = False
        self.lock = threading.Lock()

HI = None

def is_running():
    global HI
    with HI.lock:
        return HI.running

def my_stop_func():
    global HI
    with HI.lock:
        HI.running = False

def start_threads():
    global HI
    HI = Hello()
    with HI.lock:
        HI.running = True

def main():
    # init code etc...
    start_threads()

    while is_running():
        pass  # Implement your thread monitoring or other logic here

# main()  # Uncomment to run the main function

In the modifications, I’ve added a lock to ensure that access to HI.running is thread-safe, and you’d use with HI.lock: whenever its required for you to read/write to HI.running – this way you ensure that the check and the update of the running state are atomic operations from the perspective of your threads

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