I have defined a class, Test
, one of the methods of which, updater
, is run in a separate thread and continuously updates the property, steps
. I am hoping for some definitive advice regarding safe modification of the property, and safe access of the property in other threads.
Below is some working code that fulfils my requirements, making liberal use of a thread lock as suggested here. I have deployed the lock in both thread, and get and set methods since operations on the property steps
in all are non-atomic (or most likely will be in my finished code).
from threading import Thread, Lock
from time import sleep
class Test:
def __init__(self):
self.lock = Lock()
self.steps = 5
self.thread = Thread(target=self.updater)
self.threadRun = True
self.thread.start()
def updater(self):
while self.threadRun:
with self.lock:
self.steps += 1
sleep(0.001)
print('Thread stopped')
def get_steps(self):
with self.lock:
return self.steps
def set_steps(self, steps):
with self.lock:
self.steps = steps
I understand that accessing instance properties directly is preferred over using getter and setter methods:
a = Test()
steps = a.steps
a.steps = 5
rather than:
a = Test()
steps = a.get_steps()
a.set_steps(5)
but I have used them here so I can include the lock. I am not certain of the atomicness of direct access of the property in this case so might be able to avoid the lock, but can someone confirm if this is the case? If I still have to use the lock, and use getter and setter methods for each of the properties I want to access, how do I deploy a decorator within the class to make this smarter when I scale up to multiple properties? I expect something like this:
from threading import Thread, Lock
from time import sleep
class Test:
def __init__(self):
self.lock = Lock()
self.steps = 5
self.thread = Thread(target=self.updater)
self.threadRun = True
self.thread.start()
def updater(self):
while self.threadRun:
with self.lock:
self.steps += 1
sleep(0.001)
print('Thread stopped')
def locker(self, func):
with self.lock:
return func
@locker
def get_steps(self):
return self.steps
@locker
def set_steps(self, steps):
self.steps = steps
But at this point my skill at argument handling between classes and decorators comes up short and I get:
TypeError: locker() missing 1 required positional argument: 'func'
Some insight is here, but as per the first comment on the solution, I need to deal properly with arguments. I suppose I could put the locker function outside the class, but I was hoping to contain it within the class for neatness - I would not use it elsewhere. What's an elegant solution here?