I'm making some helper functions for the (fairly simple) UI framework I'm developing, among them, a helper to run app initialization tasks. Here's a helper class I've developed for oneshot tasks:
from threading import Lock
class Oneshot():
_running = False
_finished = False
def __init__(self, func, *args, **kwargs):
self.func = func
self.args = args
self.kwargs = kwargs
def run(self):
if self.running or self.finished:
return
self.active_lock.acquire()
self._running = True
self.active_lock.release()
self.func(*self.args, **self.kwargs)
self.active_lock.acquire()
self._running = False
self._finished = True
self.active_lock.release()
@property
def running(self):
self.active_lock.acquire()
value = self._running
self.active_lock.release()
return value
@property
def finished(self):
self.active_lock.acquire()
value = self._finished
self.active_lock.release()
return value
Is it actually thread-safe, as I intend it to be? Any other thoughts on this?
I'd also like to add a reset() method. My idea is like this:
def reset(self):
if self.running:
raise Exception("Runner can't be reset while still running")
self._finished = False
My only doubt is about whether raising an exception is the best course of action, but, since I have to signal the user that they are trying to perform an illegal action, and it's better to do it explicitly as the action user desired did not complete, I don't see a better way - do you?
self.active_lockis never assigned. \$\endgroup\$