04-17-2010 02:58 AM - edited 04-17-2010 02:59 AM
Hello.
I am using a State Machine driven by queue, using a For Loop to enqueue three States that have to be executed in sequence. The code is working fine but when I run it in Highlight Mode is possible to see that the "State 1" of the State Machine start running while the For Loop (which enqueue the elements) is still running. Is this kind of code safe?
I mean, for this example everything is working fine, but if I have SubVIs running in the States of the State Machine, would not be safer to have the For Loop execution done, before start playing with the SubVIs of the State Machine? Would a semaphore help me with that? I found this thread that discussed similar things, but I still thing that would be safer to have the For Loop done and just after that start running the State Machine.
What do you thing guys?
Thanks
Dan07
04-17-2010 03:12 AM
I mistyped.
thing=think
Sorry
Dan07
04-17-2010 11:23 AM
You can use a semaphore to protect a section of code from running until another section of code allows it. But why do you need to do that? You talk about "is this kind of code safe". Safe from what? Is there some kind of process you are trying to control that would cause a safety hazard if you have state 1 starting before you've put state 2 into the queue?
I've used queues numerous times. I've used state machine numerous times. I don't think I have yet to use a semaphore in a real world application.
04-17-2010 02:37 PM
For example: the idea is to run State 1, State 2 and Idle after I click the RUN button. Nevertheless, if inside the State 1 there is a SubVI that will evaluate the current time of the day. If the time is something between 2:30 pm and midnight, its necessary to run State 2 after the State 1, so, it's not necessary to change anything in the Queue. But if the time is not in this range, it's not necessry to run State 2 after State 1 and the SubVI inside State 1 must use the Flush option to clean the Queue totally. If I have the State 1 done and the SubVI evaluates that is not necessary to run State 2, it will try to Flush and clean the Queue totally, but the Queue is still been created inside the For Loop. In this situation a semaphore would help a lot. Am I right?
I don't have experience working with semaphores, could you show me a simple way to implant them in my code?
Thanks
Dan07
04-17-2010 03:38 PM - edited 04-17-2010 03:41 PM
Good question dan!
The code you are explaining is "SAFE". and seems like a good implementation of a basic "Producer-comsumer archetecture" Your UI stays responsive while the consumer loop does all the data manipilations. A very positive point.
I am a bit concerned about scaleability of the code since you have added a programatic "flush queue" in the consumer loop. It does what you want today but, what if you add a state that enters from another event? the flush queue tosses that element out too. and you might really want to do what the operator asked. I would do the time check in the producer loop (not much code to slow things down - just a timer call and a comparison right?) and determine if its correct to queue up the time based state(s).
Then again- I'm struck with the need for a time enabled state- will the operator expect the code to behave differently at different times? It is possible but, questionable.
By-the way.
you can exit the consumer loop based on the error out of the dequeue element. it returns when the queue is destroyed or when there is an element.
04-17-2010 04:01 PM - edited 04-17-2010 04:05 PM
The evaluation of the time of day was just an example. What really happens inside the State 1 is a code that will open a File Dialog and allow the user load a ascii file. Nevertheless, if the user closes the File Dialog the "open file operation" is cancelled and is no longer necessary to run State 2. This is the real situation. I would like to use the producer loop just to enqueue elements and not do any kind of evaluation or operations inside it.
I did a very simple test. I got the VI that I attached to the first message of this thread and put a Flush Queue inside State 1 and executed the VI in Highlight Mode. At the time that the State 1 flushed the queue, it was able to flush the State 2 out, but not the Idle. So, even with the Flush operation the Idle case was executed after State 1. I know that in the real speed execution, the enqueue operation of the For Loop is very very very fast and even if the user closes the File Dialog quickly, the whole enqueue operation by the For Loop would be done at that time. But, I think that is dangerous to let the code like that with the assumption that the For Loop will be always faster than the action of the user closing the File Dialog.
Because of that, I would prefer to add a semaphore to make sure that the whole enqueue operation by the For Loop would be complete, before the State 1 start running. What is the best design for the semaphore code you think best applies for this code?
Thanks
Dan07
04-17-2010 04:12 PM
I forgot to say that since I put the Flush operation inside State 1, I had to put the Queue wire into a Shift Register in the Consumer While Loop.
04-17-2010 04:40 PM
You can enqueue states from inside the consumer loop as well. If in the process of state 1, you decide you need to run state 2, then let state 1 enqueue it. Maybe it decides to enqueue a state 3, or not enqueue the next state at all.
Don't enqueue states just because you think you may need them, add them when you know you do, wherever that may be from. The data you enqueue could not only contain what state you want to run, and of course any data that goes with it, but also contain what state you want to run after that in the event that state 1 "passes", and perhaps another piece of data that is the state you want to run after that in the event that state 1 "fails".
04-17-2010 08:40 PM
Ravens
I've been adding some new elements to my state machine and because of that I am trying different approaches to make the code as clean as possible. I was doing some enqueue inside the consumer loop, but right now I am considering let this job for the producer loop only.
Could you add a basic semaphore code to my VI? Because with that I can be sure that the for loop will executes first, and then the consumer loop will run.
Thanks
Dan07
04-17-2010 10:38 PM
Obtain the Semaphore reference before both loops and release the reference after both loops.
Acquire the semaphore before the For Loop in you producer, and release it after the For Loop.
Acquire the senaphore after the Dequeue function in the consumer, and release it after the state is done.