C#: How do I wait for an event to be set? - c#

I want to write a synchronous test that calls into some asynchronous product tasks.
In the example below, DoSomething() is called by a separate thread, and then it sets the SomethingCompleted event.
In my test code, how do I wait for SomethingCompleted to be set?
public event Action<Result> SomethingCompleted;
public void DoSomething()
{
Something();
this.SomethingCompleted(new Result("Success"));
}

using (var evt = new ManualResetEvent()) {
Action<Result> handler = _ => evt.Set();
SomethingCompleted += handler;
evt.WaitOne();
SomethingCompleted -= handler; //cut object reference to help GC
}
If required you can unsubscribe from the event after the wait has completed. That way the event will not keep the delegate and closure instance alive.
You can extract this into a reusable helper method/extension.

// test case
public void Test()
{
var yourObj = new YourObj();
var done = false;
Result result;
yourObj.SomethingCompleted += (finalResult) => {
result=finalResult;
done=true;
};
yourObj.DoSomething();
while(!done) Thread.Sleep(200);
if(result != theExpectedResult) kaboom();
}
What about subscribing to an event and "polling" the lambda until result comes available? This should work.

You're using the wrong type of event. The event you're using is a callback. In the code you supplied, the delegates attached to the SomethingCompleted event are going to be called on the same thread as DoSomething.
What you want is thread synchronization, using an event like AutoResetEvent or ManualResetEvent, which have nothing to do with the framework/language-level event that you're using. You could do something like this:
void MainThreadProc()
{
// create thread synchronization event
using (var evt = new ManualResetEvent(false))
{
// start background operation
ThreadPool.QueueUserWorkItem(BackgroundThreadProc, evt);
// this line will block until BackgroundThreadProc sets the event
evt.WaitOne();
}
// resume main thread operations here
...
}
void BackgroundThreadProc(object o)
{
// get event from argument
var evt = (ManualResetEvent) o;
// do the deed
...
// set event to signal completion
evt.Set();
}
This is just one of a number of different ways to do this. Alternatives include Parallel LINQ or the Task Parallel Library (both of which are best used with parallel operations, not just a single background operation). If you don't want to block the main thread, look at BackgroundWorker.

Related

async await WhenAll not waiting

I'm developing WinForms App in VS2013, .NET FW 4.5.1. Here is my reduced code with inline comments about structure:
// Progress object implementing IProgress<MyProgressData>
var progressCallback = new Progress<MyProgressData>();
// listOfMyList is actually List<List<MyObject>>, which contains list of
// list of MyObject's which will be executed as tasks at once.
// For example, this would be sample structure for list of lists:
// List1
// MyObject1
// MyObject2
// MyObject3
// List2
// MyObject4
// MyObject5
// MyObject6
// List1's and List2's objects would be executed as all tasks at once, but List1 and List2 respectively
// would be executed one after another (because of resources usage inside TASK CODE)
foreach (var myItem in listOfMyList)
{
var myList = myItem.ToList();
// Create a list of tasks to be executed (20 by default; each taking from 30-60 seconds)
// Here cs is actually MyObject
var myTasks = myList.Select(cs => Task.Run(async () =>
{
// TASK CODE (using cs as an input object and using "cancellationToken.ThrowIfCancellationRequested();" inside execution to cancel executing if requested)
}, cancellationToken));
await Task.WhenAll(myTasks); // Wait for all tasks to finish
// Report progress to main form (this actually calls an event on my form)
await Task.Run(() => progressCallback.Report(new MyProgressData() { props }), CancellationToken.None);
}
As you can see, I construct progress object and then I have list of lists. Each item within top-level list should execute in serialized fashion (one after another). Each item's list elements, should execute all at once in a form of a tasks.
So far so good, all tasks start and even WhenAll waits for them. Or at least I thought so. I have put logging inside relevant methods, to show me code execution. It turns out that while progress logic (at the bottom) is executing, foreach loop starts executing another batch of tasks, which it shouldn't.
Am I missing something here? Does code for progress not block or wait for Report method to finish executing. Maybe I'm missing sth about async/await. With await we make sure that code won't continue until after method is finished? It won't block current thread, but it also won't continue executing?
Is it even possible (since its happening, it probably is), for my foreach loop to continue executing while progress reporting is still on the go?
This code resides inside an async method. It's actually called like this (lets assume this method is async MyProblematicMethod()):
while (true)
{
var result = await MyProblematicMethod();
if (result.HasToExitWhile)
break;
}
Every method up from MyProblematicMethod uses await to wait for async methods, and is not called many times.
Based on Glorin's suggestion that IProgress.Report returns immediately after firing an event handler, I've created exact copy of Progress class, which uses synchronizationContext.Send instead of Post:
public sealed class ProgressEx<T> : IProgress<T>
{
private readonly SynchronizationContext _synchronizationContext;
private readonly Action<T> _handler;
private readonly SendOrPostCallback _invokeHandlers;
public event EventHandler<T> ProgressChanged;
public ProgressEx(SynchronizationContext syncContext)
{
// From Progress.cs
//_synchronizationContext = SynchronizationContext.CurrentNoFlow ?? ProgressStatics.DefaultContext;
_synchronizationContext = syncContext;
_invokeHandlers = new SendOrPostCallback(InvokeHandlers);
}
public ProgressEx(SynchronizationContext syncContext, Action<T> handler)
: this(syncContext)
{
if (handler == null)
throw new ArgumentNullException("handler");
_handler = handler;
}
private void OnReport(T value)
{
// ISSUE: reference to a compiler-generated field
if (_handler == null && ProgressChanged == null)
return;
_synchronizationContext.Send(_invokeHandlers, (object)value);
}
void IProgress<T>.Report(T value)
{
OnReport(value);
}
private void InvokeHandlers(object state)
{
T e = (T)state;
Action<T> action = _handler;
// ISSUE: reference to a compiler-generated field
EventHandler<T> eventHandler = ProgressChanged;
if (action != null)
action(e);
if (eventHandler == null)
return;
eventHandler((object)this, e);
}
}
This means that ProgressEx.Report will wait for method to finish, before returning. Maybe not the best solution in all situations, but it worked for me in this case.
To call it, just create ProgressEx with SynchronizationContext.Current as a parameter to constructor. However, it must be created in UI thread, so the right SynchronizationContext gets passed in. E.g. new ProgressEx<MyDataObject>(SynchronizationContext.Current)

Notify when thread is complete, without locking calling thread

I am working on a legacy application that is built on top of NET 3.5. This is a constraint that I can't change.
I need to execute a second thread to run a long running task without locking the UI. When the thread is complete, somehow I need to execute a Callback.
Right now I tried this pseudo-code:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
_thread.Join();
// execute finalizer
The second option, which does not lock the UI, is the following:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
while(_thread.IsAlive)
{
Application.DoEvents();
Thread.Sleep(100);
}
// execute finalizer
Of course the second solution is not good cause it overcharge the UI.
What is the correct way to execute a callback when a _thread is complete? Also, how do I know if the thread was cancelled or aborted?
*Note: * I can't use the BackgroundWorker and I can't use the Async library, I need to work with the native thread class.
There are two slightly different kinds of requirement here:
Execute a callback once the long-running task has completed
Execute a callback once the thread in which the long-running task was running has completed.
If you're happy with the first of these, the simplest approach is to create a compound task of "the original long-running task, and the callback", basically. You can even do this just using the way that multicast delegates work:
ThreadStart starter = myLongRunningTask;
starter += () => {
// Do what you want in the callback
};
Thread thread = new Thread(starter) { IsBackground = true };
thread.Start();
That's very vanilla, and the callback won't be fired if the thread is aborted or throws an exception. You could wrap it up in a class with either multiple callbacks, or a callback which specifies the status (aborted, threw an exception etc) and handles that by wrapping the original delegate, calling it in a method with a try/catch block and executing the callback appropriately.
Unless you take any special action, the callback will be executed in the background thread, so you'll need to use Control.BeginInvoke (or whatever) to marshal back to the UI thread.
I absolutely understand your requirements, but you've missed one crucial thing: do you really need to wait for the end of that thread synchronously? Or maybe you just need to execute the "finalizer" after thread's end is detected?
In the latter case, simply wrap the call to myLongRunningTask into another method:
void surrogateThreadRoutine() {
// try{ ..
mytask();
// finally { ..
..all 'finalization'.. or i.e. raising some Event that you'll handle elsewhere
}
and use it as the thread's routine. That way, you'll know that the finalization will occur at the thread's and, just after the end of the actual job.
However, of course, if you're with some UI or other schedulers, the "finalization" will now run on yours thread, not on the "normal threads" of your UI or comms framework. You will need to ensure that all resources are external to your thread-task are properly guarded or synchronized, or else you'll probably clash with other application threads.
For instance, in WinForms, before you touch any UI things from the finalizer, you will need the Control.InvokeRequired (surely=true) and Control.BeginInvoke/Invoke to bounce the context back to the UI thread.
For instance, in WPF, before you touch any UI things from the finalizer, you will need the Dispatcher.BeginInvoke..
Or, if the clash could occur with any threads you control, simple proper lock() could be enough. etc.
You can use a combination of custom event and the use of BeginInvoke:
public event EventHandler MyLongRunningTaskEvent;
private void StartMyLongRunningTask() {
MyLongRunningTaskEvent += myLongRunningTaskIsDone;
Thread _thread = new Thread(myLongRunningTask) { IsBackground = true };
_thread.Start();
label.Text = "Running...";
}
private void myLongRunningTaskIsDone(object sender, EventArgs arg)
{
label.Text = "Done!";
}
private void myLongRunningTask()
{
try
{
// Do my long task...
}
finally
{
this.BeginInvoke(Foo, this, EventArgs.Empty);
}
}
I checked, it's work under .NET 3.5
You could use the Observer Pattern, take a look here:
http://www.dofactory.com/Patterns/PatternObserver.aspx
The observer pattern will allow you, to notify other objects which were previously defined as observer.
A very simple thread of execution with completion callback
This does not need to run in a mono behavior and is simply used for convenience
using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class ThreadTest : MonoBehaviour
{
private List<int> numbers = null;
private void Start()
{
Debug.Log("1. Call thread task");
StartMyLongRunningTask();
Debug.Log("2. Do something else");
}
private void StartMyLongRunningTask()
{
numbers = new List<int>();
ThreadStart starter = myLongRunningTask;
starter += () =>
{
myLongRunningTaskDone();
};
Thread _thread = new Thread(starter) { IsBackground = true };
_thread.Start();
}
private void myLongRunningTaskDone()
{
Debug.Log("3. Task callback result");
foreach (int num in numbers)
Debug.Log(num);
}
private void myLongRunningTask()
{
for (int i = 0; i < 10; i++)
{
numbers.Add(i);
Thread.Sleep(1000);
}
}
}
Try to use ManualRestEvent to signal of thread complete.
Maybe using conditional variables and mutex, or some functions like wait(), signal(), maybe timed wait() to not block main thread infinitely.
In C# this will be:
void Notify()
{
lock (syncPrimitive)
{
Monitor.Pulse(syncPrimitive);
}
}
void RunLoop()
{
for (;;)
{
// do work here...
lock (syncPrimitive)
{
Monitor.Wait(syncPrimitive);
}
}
}
more on that here:
Condition Variables C#/.NET
It is the concept of Monitor object in C#, you also have version that enables to set timeout
public static bool Wait(
object obj,
TimeSpan timeout
)
more on that here:
https://msdn.microsoft.com/en-us/library/system.threading.monitor_methods(v=vs.110).aspx

Invoke event on MainThread from worker thread

I'm having trouble invoking an event from a secondary thread in the main thread. The event handler is not executed on main thread. Can anyone give me some pointers on what I'm doing wrong.
Thanks
namespace ThreadSyncExample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("MainThread: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
Execute execThe = new Execute();
execThe.FinishedThread += (src, arg) =>
{
//This shoould be executed on MainThread right?
Console.WriteLine("Thread Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
};
execThe.Run();
Console.ReadKey();
}
}
class Execute
{
public void Run()
{
Thread exec = new Thread(() =>
{
Console.WriteLine("Worker Thread : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
OnFinishedThread();
});
exec.Start();
}
public event EventHandler FinishedThread;
protected virtual void OnFinishedThread()
{
if (null != FinishedThread)
{
EventArgs args = new EventArgs();
FinishedThread(this, EventArgs.Empty);
}
}
}
}
C# events are basically just an easy-to-use collection of delegates and "firing" an event just causes the runtime to loop through all of the delegates and fire them one at a time.
So your OnFinishedThread event handler is getting called on the Worker thread.
If you want your event on the main thread, you have to Invoke() it.
EDIT :
It appears that you don't have access to forms, or WPF (so you don't have access to Invoke() either)
So you have to manually marshall the call to the main thread by thread synchronization process. It's generally a pain.
Probably the easiest solution would be to simply use a BackgroundWorker because this way you no longer need to manualy marshal the calls to the main thread.
var worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
// call the XYZ function
e.Result = XYZ();
};
worker.RunWorkerCompleted += (sender, e) =>
{
// use the result of the XYZ function:
var result = e.Result;
// Here you can safely manipulate the GUI controls
};
worker.RunWorkerAsync();
the FinishedThread() event handler will be executed on the same thread as Execute.Run() is executed on. Just because you defined the body of the FinishedThread event handler in main() doesn't mean that main() somehow defines it's execution context.
Some mechanisms you can use to perform thread marshalling:
Use a system.windows.forms.control and use the Invoke method to marshal a function call back to the thread the control was created on. Under the hood, this will use features of the Windows Message Loop to handle the actual marshal
Use synchronization primitives to handle the marshalling manually.
Rather than re-iterate what has already been stated, check this answer for more information on marshalling:
Marshall to a thread manually

How to block until an event is fired in c#

After asking this question, I am wondering if it is possible to wait for an event to be fired, and then get the event data and return part of it. Sort of like this:
private event MyEventHandler event;
public string ReadLine(){ return event.waitForValue().Message; }
...
event("My String");
...elsewhere...
var resp = ReadLine();
Please make sure whatever solution you provide returns the value directly rather than getting it from something else. I'm asking if the method above is available in some way. I know about Auto/ManuelResetEvent, but I don't know that they return the value directly like I did above.
Update: I declared an event using MyEventHandler (which contains a Message field). I have a method in another thread called ReadLine waiting for the event to fire. When the event fires the WaitForValue method (part of the event handling scene) returns the event args, which contains the message. The message is then returned by ReadLine to whatever had called it.
The accepted answer to that question I asked was what I did, but it just doesn't feel quite right. It almost feels like something could happen to the data between the ManuelResetEvent firing and the program retrieving the data and returning it.
Update: The main problem with the Auto/ManualResetEvent is that it is too vulnerable. A thread could wait for the event, and then not give enough time for anyone else to get it before changing it to something else. Is there a way to use locks or something else? Maybe using get and set statements.
If the current method is async then you can use TaskCompletionSource. Create a field that the event handler and the current method can access.
TaskCompletionSource<bool> tcs = null;
private async void Button_Click(object sender, RoutedEventArgs e)
{
tcs = new TaskCompletionSource<bool>();
await tcs.Task;
WelcomeTitle.Text = "Finished work";
}
private void Button_Click2(object sender, RoutedEventArgs e)
{
tcs?.TrySetResult(true);
}
This example uses a form that has a textblock named WelcomeTitle and two buttons. When the first button is clicked it starts the click event but stops at the await line. When the second button is clicked the task is completed and the WelcomeTitle text is updated. If you want to timeout as well then change
await tcs.Task;
to
await Task.WhenAny(tcs.Task, Task.Delay(25000));
if (tcs.Task.IsCompleted)
WelcomeTitle.Text = "Task Completed";
else
WelcomeTitle.Text = "Task Timed Out";
You can use ManualResetEvent. Reset the event before you fire secondary thread and then use the WaitOne() method to block the current thread. You can then have secondary thread set the ManualResetEvent which would cause the main thread to continue. Something like this:
ManualResetEvent oSignalEvent = new ManualResetEvent(false);
void SecondThread(){
//DoStuff
oSignalEvent.Set();
}
void Main(){
//DoStuff
//Call second thread
System.Threading.Thread oSecondThread = new System.Threading.Thread(SecondThread);
oSecondThread.Start();
oSignalEvent.WaitOne(); //This thread will block here until the reset event is sent.
oSignalEvent.Reset();
//Do more stuff
}
A very easy kind of event you can wait for is the ManualResetEvent, and even better, the ManualResetEventSlim.
They have a WaitOne() method that does exactly that. You can wait forever, or set a timeout, or a "cancellation token" which is a way for you to decide to stop waiting for the event (if you want to cancel your work, or your app is asked to exit).
You fire them calling Set().
Here is the doc.
If you're happy to use the Microsoft Reactive Extensions, then this can work nicely:
public class Foo
{
public delegate void MyEventHandler(object source, MessageEventArgs args);
public event MyEventHandler _event;
public string ReadLine()
{
return Observable
.FromEventPattern<MyEventHandler, MessageEventArgs>(
h => this._event += h,
h => this._event -= h)
.Select(ep => ep.EventArgs.Message)
.First();
}
public void SendLine(string message)
{
_event(this, new MessageEventArgs() { Message = message });
}
}
public class MessageEventArgs : EventArgs
{
public string Message;
}
I can use it like this:
var foo = new Foo();
ThreadPoolScheduler.Instance
.Schedule(
TimeSpan.FromSeconds(5.0),
() => foo.SendLine("Bar!"));
var resp = foo.ReadLine();
Console.WriteLine(resp);
I needed to call the SendLine message on a different thread to avoid locking, but this code shows that it works as expected.
Try it : e.Handled = true; It works to prevent KeyEventArgs, for example.

Telling the timer object to invoke its "Elapsed" event asynchronously

There are times in my application, when I need to invoke my timer manually.
I've tried the following:
int originalInterval = t.Interval;
t.Interval = 0;
t.Interval = originalInterval;
but it wasn't consistent.
I've created a new timer, inheriting from System.Timers.Timer, and exposed a "Tick" method - but the problem was that the "Elapsed" event then fired synchronously.
When I implemented the "Tick" with a new Thread - the results were, again, not consistent.
Is there a better way to implement it?
I once had the same problem, so I used the AutoResetEvent to know if the Elapsed was invoked successfully:
/// <summary>
/// Tickable timer, allows you to manually raise a 'Tick' (asynchronously, of course)
/// </summary>
public class TickableTimer : System.Timers.Timer
{
public new event ElapsedEventHandler Elapsed;
private System.Threading.AutoResetEvent m_autoResetEvent = new System.Threading.AutoResetEvent(true);
public TickableTimer()
: this(100)
{
}
public TickableTimer(double interval)
: base(interval)
{
base.Elapsed += new ElapsedEventHandler(TickableTimer_Elapsed);
}
public void Tick()
{
new System.Threading.Thread(delegate(object sender)
{
Dictionary<string, object> args = new Dictionary<string, object>
{
{"signalTime", DateTime.Now},
};
TickableTimer_Elapsed(this, Mock.Create<ElapsedEventArgs>(args));
}).Start();
this.m_autoResetEvent.WaitOne();
}
void TickableTimer_Elapsed(object sender, ElapsedEventArgs e)
{
m_autoResetEvent.Set();
if (this.Elapsed != null)
this.Elapsed(sender, e);
}
}
It feels like you should look at your design a bit. Typically I try to avoid having the event handler method contain the actual work being done, but I rather try to let it be just a trigger, calling some other method that performs the work. That way you can invoke that other method from anywhere else as well:
private void Timer_Tick(object sender, EventArgs e)
{
new Thread(MethodThatDoesTheWork).Start();
}
private void MethodThatDoesTheWork()
{
// actual work goes here
}
Now, you can invoke MethodThatDoesTheWork from anywhere else within the class (either synchronously or asynchronously using a separate thread).
Alternatively, if MethodThatDoesTheWork should always be an asynchronous call, you can spawn the thread inside that method instead:
private void MethodThatDoesTheWork()
{
new Thread(() =>
{
// work code goes here
}).Start();
}
In these samples I have manually created threads. You can use that approach, the ThreadPool, Task or whatever other method of calling code asychronously, whichever fits best in your context.
Normally you shouldn’t need to fire a timer manually — you can always just run the event itself in a new thread. By and large, that’s basically what the timer does, and since you want to fire it manually, you don’t need the timer (for that manual invocation).
You didn’t specify any details as to what you mean by “not consistent”. The following should normally work:
Thread thread = new Thread(myDelegate);
thread.Start();
Of course, myDelegate can be a lambda in case you need to pass parameters:
Thread thread = new Thread(() => myMethod(param1, param2));
thread.Start();

Categories