Wait for a number of events before continuing (threadsafe) - c#

I have an integration test, where I trigger things by sending off an event. Then a couple of asynchronous things happen, and I expect a specific number of events to be raised by this.
My test code shall wait until this number of events were raised. I did this with a callback subscription to this event and a wait handle. Basically
private AutoResetEvent thingsChangedEventOccurred = new AutoResetEvent(false);
private void OnThingsChangedEventOccurred(ThingsChangedEventData thingsChangedEventData)
{
this.thingsChangedEventOccurred.Set();
}
private void WaitForThisNumberOfThingsChangedEvents(int numberOfEventsToWaitFor)
{
for (int eventsCaptured = 0; eventsCaptured < numberOfEventsToWaitFor; eventsCaptured++)
{
Assert.IsTrue(this.thingsChangedEventOccurred.WaitOne(60000));
}
}
And somewhere after I sent off the events that start things I call the WaitFor.. Method.
I realize now that this implementation has its problems with threading. I assume the AutoResetEvent can only count to one. Any ideas or patterns on how to make this thread safe?
I thought about making the eventsCaptured a field... butwell, that is kind of uncool for other reasons.

I think you're looking for CountdownEvent.
Basically, you initialize a CountdownEvent with the number of events you're expecting. Then, as each event occurs, the code signals the CountdownEvent, which will become set after it's been signaled the expected number of times.
It's a pretty handy thing. Definitely check it out.

Related

How to make thread safe event handler

In my application I have a queue which fires notifications whenever there are any changes to the queue, but sometimes it happens that when there are simultaneous operations on the queue event handler that it fires multiple times and that's okay, but what I don't want is,...
Below is the code for the event handler:
private async void NotificationQueue_Changed(object sender, EventArgs e)
{
if (!IsQueueInProcess)
await ProcessQeueue();
}
In ProcessQueue method I am setting IsQueueInProcess to true and whenever it gets completed it is set to false. Now, the problem is that whenever multiple event notifications fire simultaneously multiple ProcessQeueue methods start executing, which I don't want. I want to make sure that there will be only one execution of ProcessQeueue at any given time.
Given your statement that this event is raised whenever there are any changes to the queue, and that the queue can be used concurrently (i.e. there are multiple producers adding things to the queue), it seems likely to me that the best way to address this would be to abandon the event-based behavior altogether. Instead, using BlockingCollection<T>, with a thread dedicated to processing the queue via GetConsumingEnumerable(). That method will block the thread as long as the queue is empty, and will allow the thread to remove and process items in the queue any time any other thread adds something to it. The collection itself is thread-safe, so using that you would not require any additional thread synchronization (for the handling of the queue, that is…it's possible processing an item involves thread interactions, but there's nothing in your question that describes that aspect, so I can't say one way or the other anything about that).
That said, taking the question literally, the simplest approach would be to include a semaphore:
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
private async void NotificationQueue_Changed(object sender, EventArgs e)
{
if (_semaphore.Wait(0))
{
await ProcessQueue();
_semaphore.Release();
}
}
The above attempts to acquire the semaphore's lock. With a timeout of 0 milliseconds, it will return immediately even if the semaphore could not be acquired. The return value indicates whether the semaphore was successfully acquired or not.
In this way, as long as there is no outstanding queue-processing operation, the current event handler invocation can acquire the semaphore and will call the ProcessQueue() method. When that operation completes, the continuation will release the semaphore. Until that happens, no other invocation of the event handler will be able to acquire the semaphore, and thus will not initiate processing of the queue.
I'll note that nothing here guarantees a solution to threads racing with each other that would ensure the queue is always either empty, or always has some processing operation acting on it. That's up to you, to ensure that the ProcessQueue() method has the synchronization needed to guarantee that if any thread has modified the queue and caused this event to be raised, that that thread will not fail to initiate another round of processing should the first round not be able to observe the change.
Or put another way, you need to make sure that for any thread that is going to raise that event, either its change to the queue will be observed by the current processing operation, or that thread will initiate a new one.
There's not enough context in your question for anyone to be able to address that concern specifically. I will just point out that it's a common enough thing for someone to overlook when trying to implement this sort of system. IMHO, all the more reason to just have a dedicated thread using BlockingCollection<T> to consume elements added to the queue. :)
See also the related question How to avoid reentrancy with async void event handlers?. This is a slightly different question, in that the accepted answer causes each invocation of the event handler to result in the operation initiated by the event handler. Your scenario is simpler, since you simply want to skip initiation of a new operation, but you may still find some useful insight there.
I agree with Peter that abandoning event-based notifications is the best solution, and that you should move to a producer/consumer queue. However, I recommend one of the TPL Dataflow blocks instead of BlockingCollection<T>.
In particular, ActionBlock<T> should work quite nicely:
private readonly ActionBlock<T> notificationQueue = new ActionBlock<T>(async t =>
{
await ProcessQueueItem(t);
});
By default, TPL Dataflow blocks have a concurrency limit of 1.

How Synchronous/blocking are Events/Delegate subscriptions?

How is this code going to behave through processing time ? (i.e, how synchronous is it ?)
public delegate void FooDelegate(bytes[] data);
public event FooDelegate FooEvent;
FooEvent += new FooDelegate(Process_X);
FooEvent += new FooDelegate(Process_Y);
FooEvent += new FooDelegate(Process_Z);
while (receiving)
{
byte[] data = getRealTimeData();
StopWatch.Start();
FooEvent(data);
StopWatch.Stop();
Console.Write(StopWatch.Elapsed.Millisec));
StopWatch.Reset();
}
I have a couple of questions :
Will the call to FooEvent result in calling each subscription process sequentially/synchornously ? (Probably yes...)
Assuming each Process_N takes a long while to finish, will the call to each one block the chain (i.e the call to the next one) until it has finished ? If this is true, How to make the event call Processes X, Y, Z in a parallel fashion an then wait for all of them to finish, rather than calling them one by one and sequentially waiting for each one to finish ?
A few confirmations :
If the number of subscribers gets very high, I guess the Time printed by the StopWatch will get higher
If the processing logic in Process_N gets heavier, it will also affect the Time printed by the StopWatch
It looks like you'd benefit from parallelisation of your event handlers, as they will indeed execute sequentially and synchronously.
To create your custom event handlers you might write:
public event FooDelegate FooEvent
{
add
{
// code to add an event handler
}
remove
{
// code to remove an event handler
}
}
See the following questions for more information on what to do with the custom event handlers:
Events with Task Parallel Library for .NET 4+
How to process events in parallel
Parallel event handling in C#
etc.
and Jon Skeet's page on delegates and events.
1: yes
2: yes
It has to events might return results.
But: you should implement your event-handlers in a way so that they don't take long to run!
If they have to do heavy lifting consider running the computation in a task that get's started in your event-handeler.

Marshalling Events Across Threads

I imagine this may be marked as repetitious and closed, but I cannot for the life of me find a clear, concise answer to this question. All the replies and resources deal almost exclusively with Windows Forms and utilizing pre-built utility classes such as BackgroundWorker. I would very much like to understand this concept at its core, so I can apply the fundamental knowledge to other threading implementations.
A simple example of what I would like to achieve:
//timer running on a seperate thread and raising events at set intervals
//incomplete, but functional, except for the cross-thread event raising
class Timer
{
//how often the Alarm event is raised
float _alarmInterval;
//stopwatch to keep time
Stopwatch _stopwatch;
//this Thread used to repeatedly check for events to raise
Thread _timerThread;
//used to pause the timer
bool _paused;
//used to determine Alarm event raises
float _timeOfLastAlarm = 0;
//this is the event I want to raise on the Main Thread
public event EventHandler Alarm;
//Constructor
public Timer(float alarmInterval)
{
_alarmInterval = alarmInterval;
_stopwatch = new Stopwatch();
_timerThread = new Thread(new ThreadStart(Initiate));
}
//toggles the Timer
//do I need to marshall this data back and forth as well? or is the
//_paused boolean in a shared data pool that both threads can access?
public void Pause()
{
_paused = (!_paused);
}
//little Helper to start the Stopwatch and loop over the Main method
void Initiate()
{
_stopwatch.Start();
while (true) Main();
}
//checks for Alarm events
void Main()
{
if (_paused && _stopwatch.IsRunning) _stopwatch.Stop();
if (!_paused && !_stopwatch.IsRunning) _stopwatch.Start();
if (_stopwatch.Elapsed.TotalSeconds > _timeOfLastAlarm)
{
_timeOfLastAlarm = _stopwatch.Elapsed.Seconds;
RaiseAlarm();
}
}
}
Two questions here; primarily, how do i get the event to the main thread to alert the interested parties of the Alarm event.
Secondarily, regarding the Pause() method, which will be called by an object running on the main thread; can i directly manipulate the Stopwatch that was created on the background thread by calling _stopwatch.start()/_stopwatch.stop(). If not, can the main thread adjust the _paused boolean as illustrated above such that the background thread can then see the new value of _paused and use it?
I swear, I've done my research, but these (fundamental and critical) details have not made themselves clear to me yet.
Disclaimer: I am aware that there are classes available that will provide the exact particular functionality that I am describing in my Timer class. (In fact, I believe the class is called just that, Threading.Timer) However, my question is not an attempt to help me implement the Timer class itself, rather understand how to execute the concepts that drive it.
Note: im writing this here because theres not enough space on comments, this is of course not a complete, nor half a complete answer:
I've always used Events to signal unrelated code to do something, so that was how I described my intent. Forgive me though, I'm not sure I see the difference between marshaling and event versus marshaling another type of data (signal).
Conceptually both can be treated as events. The difference between using provided sync/signalining objects and trying to implement something like this by urself, is who and how gets the job done.
An event in .net is just a delegate, a list of pointers to methods that should be executed when the provider of the event fires it.
What youre talking about (marshalling the event), if i understand you correctly, is sharing the event object when something happens, while the concept of signalig usually talks about an object which is shared to start with, and both threads "know" something happened by checking its state either manualy or automatily (relying on provided tools by both .net and windows).
In the most basic scenario, you can implement such a signaling concept by using a boolean variable, with one thread constantly looping to check if the value of the boolean is true, and another setting to such, as a way to signal something happend. The different signaling tools provided by .NET do this in a less resource-wasting maner, by also not executing the waiting thread, as long as theres no signal (the boolean equals to false), but conceptually, it is the same idea.
You cannot magically execute code on an existing thread.
Instead, you need the existing thread to explicitly execute your code, using a thread-safe data structure to tell it what to do.
This is how Control.Invoke works (which is in turn how BackgroundWorker works).
WiinForms runs a message loop in Application.Run() which looks roughly like this:
while(true) {
var message = GetMessage(); //Windows API call
ProcessMessage(message);
}
Control.Invoke() sends a Windows message (using thread-safe message passing code within Windows) telling it to run your delegate. ProcessMessage (which executes on the UI thread) will catch that message and execute the delegate.
If you want to do this yourself, you will need to write your own loop. You can use the new thread-safe Producer-Consumer collections in .Net 4.0 for this, or you can use a delegate field (with Interlocked.CompareExchange) and an AutoResetEvent and do it yourself.

how to handle this race condition?

in my class i use a BackgroundWorker. at some point i need to cancel the asynchronous operation that can be in progress and start another one immediately. the code follows. one thing that i am not sure about is the race condition that can occur if the worker completes right before i assign my lambda to RunWorkerCompleted event. if this happens my lambda will never get called. the comment in the code shows this place. any comments on how to handle this?
thanks
konstantin
if (this.worker.IsBusy)
{
RunWorkerCompletedEventHandler f = null;
f = (s, v) =>
{
this.RunWorkerCompleted -= f;
this.worker.RunWorkerAsync();
};
// what if worker completes right before the following statement?
this.worker.RunWorkerCompleted += f;
this.worker.CancelAsync();
}
else
{
this.worker.RunWorkerAsync();
}
As long as this code runs on the main thread then there is no race. A BGW can only complete when the RunWorkerCompleted event handler finished running. The handler cannot start running until the main thread re-enters the message loop.
There's another kind of race though, induced by the else clause. You let the BGW start without a RunWorkerCompleted event handler. Now it can complete asynchronously since it won't be blocked. Always subscribe the event, test e.Cancelled to know what happened.
You could just add the RunWorkerCompleted event handler once in the ctor and also add a bool member variable 'restart' to the class. Then you can write if(IsBusy) restart = true and in your handler you check if(restart) Run(). You can define restart as volatile to avoid race conditions in that case.
I think it is not a good practice to add and remove event handlers in your case.
Maybe i'm just not smart enough to understand your code. But in my world i would built up a Queue<Action> and fill in all jobs that have to be done.
Another thread (or BackgroundWorker) will take a look at this Queue and process all the jobs in the queue sequentially (like my answer here). Maybe this is not very elegant due to the pull-mode by using a Thread.Sleep(1) in a loop.
But this could be accomplished by creating a BindingQueue<T> that derived from Queue<T> and implements IBindingList. So you could just wait for such an event, dequeue and invoke an Action till the queue is empty and start over again.

Using threads to count the loops in C# events

EDIT: It is not a listbox. My mistake. It is a list view.
I have a list view control that's driving me nuts. It is a multi-select list box, so if the user selects 5000 rows, then de-selects them by selecting a single row, the SelectedIndexChanged fires 5001 times. This causes my app to hang.
I'm trying to use threads to count the number of times that the event WOULD have fired, and then letting the last iteration do all the actual work.
Here's the code I started with. The big catch: I need the "do fancy calculations" to be in the same thread as the calling events due to items out of my control.
EDIT: I know that this code doesn't work. The Join() blocks the current thread which negates the entire purpose of creating the thread. My question is : How do I do something LIKE this.
My biggest problem isn't creating the thread. It's that my "do fancy" has to be in the same thread.
void IncrPaintQueue()
{
PaintQueue++;
Thread.Sleep(100);
}
int PaintQueue = 0;
private void SegmentList_SelectedIndexChanged(object sender, EventArgs e)
{
// We need to know how many threads this may possibly spawn.
int MyQueue = PaintQueue;
// Start a thread to increment the counter.
Thread Th = new Thread(IncrPaintQueue);
Th.IsBackground = true;
Th.Start();
Th.Join();
// if I'm not the last thread, then just exit.
// The last thread will do the right calculations.
if (MyQueue != PaintQueue - 1)
return;
// Reset the PaintQueue counter.
PaintQueue = 0;
// ... do fancy calculations here...
}
I remember solving this issue before:
A better way perhaps for you would be
to put a minimal delay in your
ItemSelectionChange Handler. Say --
50ms. Use a timer, Once the selection
changes, restart the timer. If the
selection changed more than once
within the delay period, then the
original is ignored, but after the
delay has expired, the logic is
executed.
Like this:
public class SelectionEndListView : ListView
{
private System.Windows.Forms.Timer m_timer;
private const int SELECTION_DELAY = 50;
public SelectionEndListView()
{
m_timer = new Timer();
m_timer.Interval = SELECTION_DELAY;
m_timer.Tick += new EventHandler(m_timer_Tick);
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
// restart delay timer
m_timer.Stop();
m_timer.Start();
}
private void m_timer_Tick(object sender, EventArgs e)
{
m_timer.Stop();
// Perform selection end logic.
Console.WriteLine("Selection Has Ended");
}
}
A possible solution is to delay the work, so you know whether or not more events have fired. This assumes the order of the selections is not important; all that matters is the current state.
Instead of doing the work as soon as the event fires, set up a timer to do it a couple milliseconds after the event fires. If the timer is already running, do nothing. In this way the user should perceive no difference, but the actions will not hang.
You could also do the work on another thread, but have a flag to indicate work is being done. If, when the selection event fires, work is still being done you set a flag that indicates the work should be repeated. Setting 'repeat_work' to true 5000 times is not expensive.
I get the impression that you're trying to solve a problem through brute force. I would suggest trying a different event:
private void myListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
if (e.IsSelected)
{
// do your logic here
}
}
I would suggest avoiding creating threads if at all possible, since they have overheaad. I couldn't see from your example where there's any need for parallelism.
First, while you are properly synchronizing access to PaintQueue, I feel it was more by chance in this situation as opposed to design. If you have other code accessing PaintQueue on other threads, then you have a problem.
Second, this code makes no sense. You are spooling up a new thread, incrementing the value on that thread, and then waiting for 1/10th of a second. The thing is, the code that kicks off the thread is waiting on that thread to complete. Because of this, you are just waiting in the UI thread for nothing.
Even if you queue the SelectedIndexChange events, you aren't going to be able to prevent your app from hanging. The SelectedIndexChange event is going to fire every time that you select an item, and if the user selects 5000 items, then you need to process all 5000 events. You could give them a window (process every n seconds or whatever) but that's rather arbitrary and you put the user on a timer, which is bad.
What you should do is not tie the operation to the SelectedIndexChanged event. Rather, have the user select the items and then have them perform some other action (click a button, for example) which will work on the selected items.
Your app will still hang though if you have to process a number of items for a lengthy period of time on the UI thread, but at least selecting the items won't hang.
You don't really achieve any kind of concurrency by starting a new thread and then immediately Joining it. The only "effect" of the code above is that you method is run by another thread.
Additionally, if you want to use a background thread and safe the rather expensive cost of newing a thread, you should employ the thread pool.

Categories