Reputation: 457
In the test code below,
class1.stop_callback() sets class1.stop = True
therefore class2.stop = True
therefore class3.stop should be True but it isn't.
class1.stop_callback() should stop the program but it doesn't do that. What am I doing wrong?
You can test the code on repl.it https://repl.it/@bahtsiz_bedevi/classtest
import threading
import time
class Class1(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop = False
def stop_callback(self):
self.stop = True
def run(self):
class2 = Class2()
class2.stop = self.stop
class2.start()
while True:
time.sleep(1)
print("{} stop status: {}".format(self.__class__, "True" if self.stop else "False"))
if self.stop:
break
class Class2(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop = False
def run(self):
class3 = Class3()
class3.stop = self.stop
while True:
time.sleep(1)
print("{} stop status: {}".format(self.__class__, "True" if self.stop else "False"))
if self.stop:
break
class3.foo()
class Class3:
def __init__(self):
self.stop = False
def foo(self):
while True:
time.sleep(1)
print("{} stop status: {}".format(self.__class__, "True" if self.stop else "False"))
if self.stop:
break
class1 = Class1()
class1.start()
for i in range(10):
time.sleep(1)
class1.stop_callback()
Upvotes: 1
Views: 78
Reputation: 141
Since Class3
is not a Thread
-like class (despite not running in the main thread) you cannot change the value of class3.stop
until class3.foo()
returns. Since class3.foo()
doesn't return until the value of class3.stop
changes, there is no way to stop the process and it runs forever.
I would suggest basing Class3
on Thread
so that you can call methods on it while it is running. If this is too much overhead, or you will be running it more than once per instance of class2
, you could always just define foo
and then run it within the Class2.run
method.
EDIT: I was going to mention Florian's point, but since - as in his proposed solution - mutable objects do carry across during assignments, I wasn't sure if you had already thought this part through.
Below is revised code; note
threading.Lock
to prevent those weird print statements that were happening on the same linewhile not self.stop
rather than if
statements with break
sClass3
import threading
import time
printLock = threading.Lock()
p = print
def print(*a, **b):
with printLock:
p(*a, **b)
class Class1(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop = False
def stopMe(self):
self.stop = True
def run(self):
class2 = Class2()
class2.start()
while not self.stop:
time.sleep(1)
print("{} stop status:{:6}".format(self.__class__, str(self.stop)))
class2.stopMe()
class Class2(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop = False
def stopMe(self):
self.stop = True
def run(self):
class3 = Class3()
class3.start()
while not self.stop:
time.sleep(1)
print("{} stop status:{:6}".format(self.__class__, str(self.stop)))
class3.stopMe()
class Class3(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop = False
def stopMe(self):
self.stop = True
def run(self):
while not self.stop:
time.sleep(1)
print("{} stop status:{:6}".format(self.__class__, str(self.stop)))
class1 = Class1()
class1.start()
time.sleep(10)
class1.stopMe()
Upvotes: 1
Reputation: 1808
In Python, variables are names for objects. By assigning False
to class1.stop
and class1.stop
to class2.stop
, you are assigning False
to class2.stop
, nothing more.
What you seem to want is a reference to class1.stop
instead, however this is not how assignment works in Python. One way to get around this would be to use a list. If you keep the list the same and only change the value at the first index, you can achieve what you want:
stop1 = [False]
stop2 = stop1
assert stop2[0] == False
stop1[0] = True
assert stop2[0] == True
Upvotes: 1