Closed mla-martin closed 4 years ago
Hi @martin-intex,
this looks like a question about how to use transitions. Please refer to Stackoverflow for such matters. Posting there has several advantages:
Your question gains higher visibility since most developers look for help there The targeted community is larger; Some people will even help you to formulate a good question People get 'rewarded' with 'reputation' to help you. You also gain reputation in case this questions pops up more frequently. It's a win-win situation.
About the first part of your question:
Actually I read the source of the LockedMachine but did not understand how the trigger function actually has knowledge of the additional thread I'd created.
it does not. Every execution of a machine method will acquire the lock and only release it when it returns. By default, LockedMachine
uses simple locks (threading.Lock
) which can only be acquired once. Calling a trigger from withing a trigger (or any other machine method) will cause a deadlock. Have a look at threading.RLock
and the relevant transition documentation how to use LockedMachine
with custom contexts.
Currently, this issue neither contains a feature request nor a bug report. I will close it for now. Feel free to comment nevertheless. If a feature request or a bug report arises, I will reopen the issue again. Additionally, if you post this question on SO, you can add the link here and notify me if the question stays unanswered for quite some time.
Hi,
it does not. Every execution of a machine method will acquire the lock and only release it when it returns. By default, |LockedMachine| uses simple locks (|threading.Lock|) which can only be acquired once.
That is what I had expected and what I also relied on. But unfortunately this is not what I see.
Based on the "lock only during the function call" I assume that the main
loop in the method
That is what I had expected and what I also relied on. But unfortunately this is not what I see. ... But actually also using a RLock as the machine context does not change the behaviour)
Just replacing Lock
with RLock
will indeed not change much.
transitions
used to use RLock
directly but due to performance issues for deeply nested events we switched to a 'lighweight' version which facilitates Lock
but only acquires the lock once for each thread and call (see #167). Without it self.to_A()
in thread_run
would never be executed because thread_run
already acquired the lock. More precisely, the whole constructor would deadlock because it could not call other machine methods.
But let's say we override the thread check (or more accurately the assigning of the thread ID) after the constructor is done (see [1] below). You can (un)comment [1] to observe the difference in behaviour.
import time
from transitions.extensions import LockedMachine as Machine
import threading
import logging
class Test(Machine):
states = ['A', 'B', 'C']
def __init__(self):
Machine.__init__(self, states=self.states,
initial='A'
)
self.thread = threading.Thread(target=self.thread_run)
Machine.__enter__ = lambda x: True # [1]
self.thread.start()
def thread_run(self):
logging.info('entering loop...')
while True:
time.sleep(1)
self.to_A() # this should spill quite some log messages
logging.basicConfig(level=logging.DEBUG)
t = Test()
# >>> INFO:root:entering loop...
# that's it
I do not think that this is what you want to achieve either.
With my current understanding of your goal, I'd still insist this is a usage and design question where Stackoverflow is the more appropriate location to ask for assistance. If posting there does not help you or indeed a bug or lacking feature is identified I am more than happy to open this issue and working with you to solve it.
Hi,
I would like to implement a transition variant that can be used with threads but does not block until a thread is done. See the simple example below. The calls in the run methods are never executed because a lock is held (due to the thread created/started) in the constructor. Actually I read the source of the LockedMachine but did not understand how the trigger function actually has knowledge of the additional thread I'd created. However - when not using the LockedMachine but the plain Machine variant the example works as expected (e.g. B->C->A->B->C->A->A->B->C) but I think it is not thread safe since the trigger method is not reentrant safe. Is there is an implementation with a reentrant safe trigger but no locking of additional threads?