Issue
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?
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:
- Initialization of
HI
: You have to ensure thatHI
is initialized before any thread actually try to access itsrunning
attribute, that's the most common issue if threads start running beforeHI
is set to an instance ofHello
; - 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. - 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. - The code that OP showed is using standard threading, not async programming, the
async
keyword and locks are more relevant in anasyncio
-based programming, so in case you want to do this you can introduce a lock in theHello
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
Answered By - str1ng
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.