I'm attempting to monitor the status of many HPC jobs running in parallel in a single threaded program, I'm subscribing to events raised by OnJobState and when monitoring as few as three jobs event state changes will go missing and the job is stuck running.
I'm assuming I need a thread per job to catch all the events but I can't find any information about the limits of events subscripton in a single thread program.
I would have thought the .net platform would queue this all up but that doesn't appear to be the case.
Events are synchronous by default. That means that the object that raises an event will continue its execution only after all event handlers finished their work. The event handlers will run on the same thread as the object that raises the event. That leads to the following conclusions:
The .NET framework can't queue anything, because the events are raised one after another
You should not do heavy computing in event handlers. If the events are fired in rapid succession, even moderate computing should be avoided.
If you want queuing, you need to implement it yourself: In your event handler, add the info about the new event to a thread safe queue and process this queue from another thread.
I made this question more general to remove the confusion over HPC, looks like I have no control over how my event hander is executed so I need to make it thread safe.
Related
I have an event that is raised from a third-party library, which executes on a background thread. This event basically notifies listeners of status updates in the system the library is watching. The handler invokes itself on the UI thread if InvokeRequired is true, and in either case then proceeds to append an entry for the status change to text in a textbox, and pop up a notification in the tray.
Now, the problem is that these status updates can come in very rapidly; the system being monitored can go from its "idle" state through several intermediates to a "ready" state in milliseconds. I need to know that the system has transitioned through all of these intermediate states; however, not all of the state changes are getting to the log. Setting a breakpoint and stepping through the handler shows the oddest behavior; the handler will step through the first couple of lines of code, and will then jump back to the method's entry. It's almost as if either the event or the Windows message pump is aborting the method call because another call to the same method is incoming. Putting the method body in a lock block does not solve it.
I've seen this before in other projects that do not use this third-party library. I wasn't as concerned there, because the rapid-fire event was simply triggering window redraws. If they all happened, great, but if one was short-circuited, there was another in the pipe that would go through. This, however, is a much more application-critical task that must happen every time the event is raised, in order (it doesn't have to happen as fast as the states actually change; definitely not expecting that).
What's the cause of this short-circuiting behavior, and how do I stop it?
What you're seeing is most likely new calls to the event handler from the background thread while the call you first started stepping through is still running.
Rather than doing all of the work synchronously in the thread the event handler fires in it would likely be beneficial to do the work in another thread.
Just wrap everything you're doing in your current event handler in a Task.Factory.StartNew, or use BeginInvoke to marshal to the UI thread instead of Invoke.
I couldn't be sure as I have no knowledge of that library, but it could be that it's unable to fire more events until it finishes executing all of the event handlers for the previous event.
Another option that you may need to do, either to solve this problem, or to prevent your UI from being mad at you for so many updates, is to take the status changes as the come in and just dump them into a collection, and then just periodically check that collection and process all of the changes in a batch. This would be easier on the event handler for the 3rd party object as it just needs to add an item to a collection, and also easier on the UI as it won't need to update several times in the span of time the monitor can even render the changes.
I have a class that fires an event at a fairly rapid frequency (every 100ms). To avoid slowing down this process, event handlers should hand off the processing to some kind of background task/thread/worker (as opposed to doing it within the event handler).
What's the best approach? Should I use Task.Factory.StartNew within the event handler? Will there be an overhead of creating tasks this rapidly (e.g. 5 event handlers will create 5 tasks every 100ms)? Or could I use a BackgroundWorker (instantiated in a subscriber's constructor), and in the event handler call the .RunAsync method?
Two ways:
Either use Task.Factory.StartNew. This method relies on the ThreadPool to minimize the task creation cost. This should be ok in most cases.
If you need to further reduce the performance impact, you can create a producer/consumer queue. When the event is triggered, enqueue a notification. On the other side, a thread monitors the queue and process the notifications as they arrive.
To set the stage, I have a custom class called Scheduler that holds multiple Task objects (this is a custom class as well). Each task has a BackgroundWorker object to run long running work. I am currently doing some testing of having many of these tasks executing quickly and being handled at the same time.
In my Task object, I raise an a custom event (TaskCompletedEvent) in the TaskWorkerCompleted handler to alert the scheduler that a task is completed. The scheduler uses the same event handler for every task's TaskCompletedEvent.
What I want to know is if I am currently in the Scheduler TaskCompletedEvent handler executing code and another event finishes up, what happens? Both are going to be on the UI Thread, so does the one currently in the event handler finish up before the other one proceeds? I'm getting confused on what is going to happen when two events finish simultaneously and need to be handled.
No, the events themselves don't know about the UI threads. So the events will be dispatched in the same thread where they are fired (this is most probably in the backgroundworker's thread, right?)
If your both events are fired in the UI thread, this cannot be simultaneous (after all, the UI thread is executing either one or another event firing code), so the second event isd perhaps going to be fired when the first event is finished with firing and dispatching.
If you want the Scheduler to marshal the events to the UI thread, that is a slightly different story. Your code which needs to be executed at the UI thread will be actually posted into a kind of event queue of that thread, and whatever event-firing code happens to be first, gets executed first.
I am working on a Messenger library. The main class has a Login method. When logging in, all contact list data is downloaded and stored until the Login has completed, at which point I raise a UserAdded event for each user that was downloaded.
Currently I raise the events right at the end of the Login method, one by one. This works, but it means if I perform a lengthy operation inside a UserAdded event handler, the library consumer does not get their events in a timely fashion.
One way around this I can see would be to raise each event asynchronously, but this would thrash the threadpool.
Am I doing it the right way currently? Should I simply make a note in the documentation warning against performing lengthy operations inside event handlers?
Perhaps you might want to change your event handler to simply "enqueue" into a threadsafe queue work items. You can then have a single thread which pumps the queue continuously to actually process the messages. That way the raise happens very quickly and there is only one thread actually processing the queue of work items.
However doing this means you now have to deal with the fact that raising your event does not mean it has been immediately processed, which could affect logic you have in your app.
I have a weird behavior in my GUI code. If the user produces a lot of events in a short time, it happens that a running event handler method gets interrupted by another event handler method.
Since everything runs in the same thread (GUI thread) everything should run sequential and an interruption should not be possible, or do I misunderstand something?
Thanks for your advise,
Eny
No, that doesn't happen. You are right in your understanding that the thread runs sequentially.
The GUI thread can be interrupted but only to run a different thread, it will not re-enter the GUI thread to handle another event. A thread only has one instruction pointer and thus can only be in one place in the code, it can not be interrupted by itself.
If you are experiencing something that look like the GUI thread is re-entered, the reason is something else.
The GUI thead can however "interrupt" itself by calling the Application.DoEvents method.
You are correct, in a single threaded application, event should be run sequentially. There are a few exceptions:
An event is fired and calls the first event handler in its subscriber list. The event handler fires an event of its own, which calls other event handlers. In this case, it would appear that the event was interrupted, but it was not. When the original event handler completes, the next event handler in the list will be called.
An event handler calls the Application.DoEvents() method. This will suspend the current event and process any messages waiting in the message queue (which will usually fire events of their own), and when it has finished processing all messages, it will return to the event. A problem may occur when Application.DoEvents() causes a recursive call to the event which called it, as a result of firing an event from one of the messages it processed.
Event handlers may be executed on different threads. Some events are not fired on the UI thread, and may fire on their own thread. This could cause events to be fired out of order and interrupt each other on a thread contexts switch. Make sure that the events you consume are fired on the UI thread, and if not, Control.Invoke() them onto the UI thread. An example of an event that is fired on a separate thread, possibly without you being aware of it, is the System.Threading.Timer.Elapsed event.