LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Register for events causes freezes if used in more than one event structure

hei,

i am getting in over my head, and i probably miss something.

but something bothers me: i dont think the dynamic event behave weirdly: each time an event is created, either one of the 2 loops uses it, and then flush the whole event structure. up to now no problem. on next event the choice is made again. i guess one would have a problem only if the 2 loops would react on the same event.

at least that is how i would like it to be.

in this special case, that means to me that the behavior presented here is a bug.

-----------------------------------------------------------------------------------------------------
... And here's where I keep assorted lengths of wires...
Message 11 of 39
(7,592 Views)


@tst wrote:

@Jim wrote:

When an event structure executes, it flushes all events in the registration (subscription queue) that are not handled by the event structure. 


That would make sense when you think about it, but is this documented anywhere?

I don't see how that would explain the behavior I described, though.



I don't think that this is documented anywhere (I'm planning on writing a series of blog articles on the subject, sometime soon, and I'll probably create a few entries in the LabVIEW Wiki, too).  This is (arguably) an implimentation detail of the User Events abstraction that is unimportant to the casual user.  The main point is that User Events implement a publish subscribe model, minus the ability to manage the actual subscriptions or subscribers.  The quirky behavior you are seeing probably has to do with the possibility that there is insufficient locking of the subscription events, in the situation where two Event Structures are dequeuing from the same event registration -- a pub-sub model allows subscribers to have multiple subscriptions but each subscription can belong to one and only one subscriber. 

Publish-subscribe systems are very complicated.  And, NI has done a very nice job of created an easy to use model that doesn't require much work on the part of the users.  That said, there are still a few things that we need in the API for it to be generally useful -- in particular, I would like to be able to specify an event registration as either a lossless infinite queue (the current behavior) and a lossy queue of size 1 (which would only output the most recent event -- kind of like a Notifier).

Message 12 of 39
(7,584 Views)

@Gabi1 wrote:

each time an event is created, either one of the 2 loops uses it, and then flush the whole event structure.


Not exactly. According to the documentation, it's not either of the loops, but at least one of the loops. The same event could be handled by more than one loop, because the loop only flushes the queue after it finishes executing the event case.

In any case, this behavior is different from the behavior of standard events, where events are queued from the moment the VI with the event structure entered one of the run states (even if it's not actually running) and where events are never flushed. It also does not appear to be documented.

Basically, as was said, the registration should be done with a seperate node separate each event structure.

BTW, just to be annoying - I found out that it IS actually the event structure that gets stuck and not just the UI by enqueuing the messages from the value change event and dequeuing them in another VI. I'm guessing that it is possible that the locking of the UI also locks the UI thread, preventing the Value Change event from being fired, but that would seem a bit weird.


___________________
Try to take over the world!
Message 13 of 39
(7,558 Views)
Okay, I still haven't (for the life of me) figured out how to quote a message other than the most recent using this forum (but I did yell a bunch of expletives at the computer), so apologies if I mess up the formatting.


@Jim Kring wrote:

When an event structure executes, it flushes all events in the registration (subscription queue) that are not handled by the event structure.  This is necessary, in order to avoid a memory leak where the subscription queue grows because there is no event structure dequeing the events, especially since there is no way to explicitly manage the subscription queue.


This is somewhat accurate. It's not that the event structure "flushes" anything.  When an event gets put in the queue (as Craig and Jim alluded, each event structure has it's own queue, which is implicitly created, and each event registration node creates a queue), we notify all event structures that are set up as consumers of that queue that something new is there.  The ES wakes up, pulls the first element off the queue, then tries to dispatch it to an appropriate event-handling case.  In the situation where there is no proper event handling case, the ES fails silently.  This is how you end up with the situation described initially: two ES read from same queue, while they are each configured to handle different events.  If the "wrong" ES wakes up first and pulls the event from the queue, it will do a no-op while the "correct" ES will see an empty queue and just go back to sleep.

It is true that the event isn't actually pulled off the queue until the event-handling case is finished.  There is a reason for this (I think), but I don't remember it off-hand. I agree that it would make more sense to pull it off at the beginning rather than the end, and have no chance of parallel event structures seeing the same event from a single queue.  However, Craig's point stands that it is bad practice to split an Event Registration Refnum wire.  This is documented.  We can't physically stop it from happening (if we could and it wouldn't break existing paradigms, we would have), so the best we can do is document it and *hope* that our users read our documentation.  The Event documentation is quite thorough, though it's obvious that most of our users are typical engineers and forego reading the manual in favor of using the  "guess and check" method instead.  I am of course guilty of this in many instances as well, so please don't take that as a criticism.

Jim: Of course you know you can get the behavior you want by passing all events from the ES into a queue and enforce a one item cap on it.  Yes, this takes more code and extra memory, but it seems like an uncommon use case.  I'm curious what types of applications would  benefit from that behavior?

Tst: No, the ES does not lock the UI thread in any way.  Again, reading the documentation might be helpful to understand what happens when "lock front panel..." is enabled for an event-handling case.  If you want clarifications after reading, I'm happy to help, but I don't have time to try to explain the whole mechanism from scratch.

HTH.

J

Jason King
LabVIEW R&D
National Instruments
Message 14 of 39
(7,551 Views)

Jason, this should not be documented only in the caveats section (which people would only read, if at all, when starting to use the event structure and not when starting to use dynamic events), but also in the Register for Events help (which I know is already quite long). This should probably be in bold font.

I realize that the UI locking should not actually lock the UI thread (which is why I said it was weird), and I only offered it as a possible explanation to why the event structure gets stuck, since this stops happening when you disable that option.

I still don't understand why the event structure gets stuck. The closest I could find was when I looked in the LV help just now and found that the help for Unregister for Events says that

"If you do not unregister for events, LabVIEW continues to generate and queue the events ... which... can hang the VI if you enable front panel locking for the events".

I can understand why it would hang the UI, but why would it hang the VI itself?
As I said in my previous post - I checked. The ES itself is locked, not just the UI.
So either whoever wrote that knew what they were talking about or they meant that the UI of the VI would hang. Either way, the original question still remains unanswered.

BTW, you can't quote multiple posts. You either have to manually copy and paste or reply several times. You can reply to each specific post by clicking the reply "button" in its top left corner.


___________________
Try to take over the world!
Message 15 of 39
(7,542 Views)


@tst wrote:

BTW, you can't quote multiple posts. You either have to manually copy and paste or reply several times. You can reply to each specific post by clicking the reply "button" in its top left corner.




A-ha.  That doesn't appear as a link to me (other than the cursor changes) on Firefox on the Mac.  Great website design we have here 😕



Jason, this should not be documented only in the caveats section (which people would only read, if at all, when starting to use the event structure and not when starting to use dynamic events), but also in the Register for Events help (which I know is already quite long). This should probably be in bold font.



Well, that is a matter of opinion I suppose.  I don't think I'm going to take a stand on this one, but feel free to file a bug against the documentation if you feel this is necessary.  As things are, us developers don't really have control over where everything (or what) ends up in the documentation, we just make suggestions.



@tst wrote:

I realize that the UI locking should not actually lock the UI thread (which is why I said it was weird), and I only offered it as a possible explanation to why the event structure gets stuck, since this stops happening when you disable that option.

I still don't understand why the event structure gets stuck. The closest I could find was when I looked in the LV help just now and found that the help for Unregister for Events says that

"If you do not unregister for events, LabVIEW continues to generate and queue the events ... which... can hang the VI if you enable front panel locking for the events".

I can understand why it would hang the UI, but why would it hang the VI itself?
As I said in my previous post - I checked. The ES itself is locked, not just the UI.
So either whoever wrote that knew what they were talking about or they meant that the UI of the VI would hang. Either way, the original question still remains unanswered.



I haven't run your VI so I can't comment specifically on the behavior you are seeing.  However, to explain what you quote from the help.  By "hang the VI" it means that the front panel UI will become (or appear) unresponsive, as the front panel will be "locked" while waiting for an event structure to process the pending events, however if no event structure is set to execute to service the events, then the front panel will never become unlocked.  It is not a comment about the execution of the VI.

Regarding your specific case, it sounds like the Event structure is not getting "locked"  or "hung" in any way. It is simply not responding to an event when you expect it to (this may be a bug - I'm not in a place to be able to look into it currently), and thus the first event it "sees" is a timeout, in the absence of any other event.  Your diagram is still executing, the the ES can still execute.  It's just not executing in response to an event you expect it to, it sounds like.  Is this correct?  I just want to make sure i understand, and that we're speaking the same language here.

J

Jason King
LabVIEW R&D
National Instruments
Message 16 of 39
(7,564 Views)


@Jason King wrote:

By "hang the VI" it means that the front panel UI will become (or appear) unresponsive, as the front panel will be "locked" ...

I figured as much, but I was trying to catch at straws for potential explanations.

Regarding your specific case, it sounds like the Event structure is not getting "locked"  or "hung" in any way. It is simply not responding to an event when you expect it to (this may be a bug - I'm not in a place to be able to look into it currently), and thus the first event it "sees" is a timeout, in the absence of any other event.  Your diagram is still executing, the the ES can still execute.  It's just not executing in response to an event you expect it to, it sounds like.  Is this correct?  I just want to make sure i understand, and that we're speaking the same language here.

Here's the code:
 
 
Loop B has the following cases:
  • reacts to a click on the boolean by firing the user event (locks the UI).
  • register for the value change event for the text control (locks the UI).
  • timeout (does nothing).
  • stop - stops.

Loop A has two cases - the one you see and the stop case.

What should happen is this - when you press the OK button, loop B fires the event. Loop A receives it and fires the value change event, which is processed by Loop B, so for each click on the OK button, the iteration display should increment twice. This works fine if you click the OK button once.

If you click it in rapid succession, though, the UI will freeze as if one of the locking events started execution and did not finish. It will only unfreeze when the timeout event executes and then it will keep executing the remaining events in its queue (during which time it could get stuck again).

So, essentially, your "It's just not executing in response to an event you expect it to" is basically the same as my "the ES is stuck" - it has events in its queue, but it's not processing them. Not only that, but the UI is actually stuck as if it's still in the middle of processing an event which locked the UI.  
I know that the release is happening due to the timeout because changing the timeout clearly changed the time it took to get released.
By the way, I just added an indicator to the timeout case to show the time of the event and the timeout event does not actually executes (which is good, because there are still other events in the queue).
 
And another BTW, which I've already mentioned - when you disable the UI locking in the two cases in loop B, this issue does not occur. As far as I recall, in the original program where I encountered this, I used a user event, but it is possible that I'm wrong and that the triggering was done by the signaling property (no, I didn't write it).

Message Edited by tst on 05-07-2007 11:43 PM


___________________
Try to take over the world!
Message 17 of 39
(7,557 Views)


@Jason King wrote:

Jim: Of course you know you can get the behavior you want by passing all events from the ES into a queue and enforce a one item cap on it.  Yes, this takes more code and extra memory, but it seems like an uncommon use case.  I'm curious what types of applications would  benefit from that behavior?

Hi Jason,

IMO, event consumers should be able to define whether they want all events or just the latest (that's why we have notifiers, in addition to queues).  Here is a simple example:

Tracking a mouse-move on a picture control: I move the mouse over a picture control -- I want to draw an item under the mouse and have the item move beneath the mouse as the mouse moves.  I want to register for mouse move events, but I don't really care about getting every event -- this brings my application to a crawl, as I get an event for every pixel that the mouse moves over.  Rather, I want to only get the latest event to know where the mouse is currently located.

I know that I can solve my problems using Queues and Notifiers -- I am stuck and I don't need a work around.  I want to use Event Structures (and User Events), but I think that they have some limitations that could be easily overcome.
Message 18 of 39
(7,550 Views)

@Jim Kring wrote:

Tracking a mouse-move on a picture control: I move the mouse over a picture control -- I want to draw an item under the mouse and have the item move beneath the mouse as the mouse moves.  I want to register for mouse move events, but I don't really care about getting every event

Definitely a good idea and something I wanted for a long time. This should also be available for static events. The way this should be defined is basically for us to be able to define some minimum bounds for firing events and a timeout. The minimum bounds would determine when events will be fired (e.g. I moved at least 10 pixels) and the timeout would determine when to fire the last event (the one which brings you to your target but which doesn't pass the minimum requirements). This would be the same for a value change on a slide (although that's easier because you can always compare to the current value).

I realize that we can do this in code, but it is very cumbersome.

Ideally, this would be dynamically configurable using the event structure nodes, but I can see how that could create a problem with backward compatibility.


___________________
Try to take over the world!
Message 19 of 39
(7,544 Views)


@Jim Kring wrote:

IMO, event consumers should be able to define whether they want all events or just the latest (that's why we have notifiers, in addition to queues).  Here is a simple example:

Tracking a mouse-move on a picture control: I move the mouse over a picture control -- I want to draw an item under the mouse and have the item move beneath the mouse as the mouse moves.  I want to register for mouse move events, but I don't really care about getting every event -- this brings my application to a crawl, as I get an event for every pixel that the mouse moves over.  Rather, I want to only get the latest event to know where the mouse is currently located.

I know that I can solve my problems using Queues and Notifiers -- I am stuck and I don't need a work around.  I want to use Event Structures (and User Events), but I think that they have some limitations that could be easily overcome.



Jim, I'm glad to hear you _want_ to use the Event Structure.  I suppose we did something right 🙂  I can certainly relate to your use case, as we had a couple of use cases that are nearly identical on the Mindstorms project.  The drag-drop behavior we did had the same issue - we needed mouse move events, but not every one - just the "latest" one so we can redraw with new location and give feedback.  The architecture we chose was a producer-consumer model where the producer loop had an ES watching for mouse move events, and it would send a user event to the consumer loop at some regular interval with the mouse location. This way we effectively throttled mouse move events (I think we used a timer of 15ms or so) so we didn't get overrun with events, but also could appear responsive to the user.  The work done to handle the mouse move event, check the time elapsed since the last user event was fired, and updating a shift register, was essentially trivial.

I agree this is not as easy as it could be, and what you describe would make it quite simple. However, use cases certainly exist for wanting every mouse move (say, allowing the user to draw a curve), so the user needs to be presented with a way to choose the behavior they would like. I know you appreciate that we have to serve a broad range of users and need to make sure that we don't overly-complicate the interface for beginning users in order to add functionality for you advanced folks.  I do think that your idea (mocked up in the other thread) of adding an input to the register for events node is a reasonable suggestion, but I haven't thought through all the peculiarities of the implementation, and really don't think it's terribly complicated to write the code I described above to get the same functionality. Of course, if you want that behavior for multiple events at once, it gets a bit more complicated.




@tst wrote:

The way this should be defined is basically for us to be able to define some minimum bounds for firing events and a timeout. The minimum bounds would determine when events will be fired (e.g. I moved at least 10 pixels) and the timeout would determine when to fire the last event (the one which brings you to your target but which doesn't pass the minimum requirements). This would be the same for a value change on a slide (although that's easier because you can always compare to the current value).

I realize that we can do this in code, but it is very cumbersome.



I disagree this is cumbersome to code. You can write it once and re-use it.  I'm sure we can come up with a bunch of esoteric special cases (move 10 pixels, any value change over x%, only if the user moves the cursor from one plot to another) that ultimately would make the configuration way too complicated to be useable.   It shouldn't be that hard to write a proxy for mouse move events to get the behavior you want.  Create a subVI that takes a VI (or control) ref and a user event (with data equivilent to a mouse move event) as input.  The VI registers for mouse move events on the reference input.  It would do any logic you want to filter the events, and would fire the user event when the criteria is met.  Run this SubVI in parallel with your main application, which will have an ES registered for the user event.  Make the VI re-entrant and you should be able to use it in multiple VIs at a time.  You'd probably want to have it watch a global or for a user event that will tell it when to terminate.

These are advanced use cases, and while I can understand wanting it to be as simple as possible, I don't think it's unreasonable to expect advanced users to have to write a bit of code to get advanced event filtering like this.  We get a lot of feature requests, and the things that aren't possible to do by writing a little code are likely to take precedence over the things that are possible, but perhaps could be easier (at the expense of a more complicated configuration/user interface, most likely).

Personally, I want to figure out how to present an API to get a "capture" so that it's easier to write your own tracking/drag-drop loops from the diagram (try doing that now, and handling the user leaving the bounds of the window, releasing the mouse outside the bounds of the window, etc).  I'd also like to see more filterable events so the diagram can override more of the built-in behaviors.  Unfortunately, only a finite amount of development time can go in to each release, so it looks like us on the LabVIEW team have some reasonable job security as we have enough feature requests to do another 20 releases or so 🙂

J

Jason King
LabVIEW R&D
National Instruments
Message 20 of 39
(7,529 Views)