Blocking and waiting for an event - c#

It sometimes want to block my thread while waiting for a event to occur.
I usually do it something like this:
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private void OnEvent(object sender, EventArgs e){
_autoResetEvent.Set();
}
// ...
button.Click += OnEvent;
try{
_autoResetEvent.WaitOne();
}
finally{
button.Click -= OnEvent;
}
However, it seems that this should be something that I could extract to a common class (or perhaps even something that already exists in the framework).
I would like to be able to do something like this:
EventWaiter ew = new EventWaiter(button.Click);
ew.WaitOne();
EventWaiter ew2 = new EventWaiter(form.Closing);
ew2.WaitOne();
But I can't really find a way to construct such a class (I can't find a good valid way to pass the event as an argument). Can anyone help?
To give an example of why this can be useful, consider something like this:
var status = ShowStatusForm();
status.ShowInsertUsbStick();
bool cancelled = WaitForUsbStickOrCancel();
if(!cancelled){
status.ShowWritingOnUsbStick();
WriteOnUsbStick();
status.AskUserToRemoveUsbStick();
WaitForUsbStickToBeRemoved();
status.ShowFinished();
}else{
status.ShowCancelled();
}
status.WaitUntilUserPressesDone();
This is much more concise and readable than the equivalent code written with the logic spread out between many methods. But to implement WaitForUsbStickOrCancel(), WaitForUsbStickToBeRemoved and WaitUntilUserPressesDone() (assume that the we get an event when usb sticks are inserted or removed) I need to reimplement "EventWaiter" each time. Of course you have to be careful to never run this on the GUI-thread, but sometimes that is a worthwhile tradeoff for the simpler code.
The alternative would look something like this:
var status = ShowStatusForm();
status.ShowInsertUsbStick();
usbHandler.Inserted += OnInserted;
status.Cancel += OnCancel;
//...
void OnInserted(/*..*/){
usbHandler.Inserted -= OnInserted;
status.ShowWritingOnUsbStick();
MethodInvoker mi = () => WriteOnUsbStick();
mi.BeginInvoke(WritingDone, null);
}
void WritingDone(/*..*/){
/* EndInvoke */
status.AskUserToRemoveUsbStick();
usbHandler.Removed += OnRemoved;
}
void OnRemoved(/*..*/){
usbHandler.Removed -= OnRemoved;
status.ShowFinished();
status.Done += OnDone;
}
/* etc */
I find that much harder to read. Admittedly, it is far from always that the flow will be so linear, but when it is, I like the first style.
It is comparable to using ShowMessage() and Form.ShowDialog() - they also block until some "event" occurs (though they will run a message-loop if they are called on the gui-thread).

I modified Dead.Rabit's class EventWaiter to handle EventHandler<T>. So you can use for waiting all events type of EventHandler<T>, that means your delegate is something like delegate void SomeDelegate(object sender, T EventsArgs).
public class EventWaiter<T>
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter(object eventContainer, string eventName)
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent(eventName);
}
public void WaitForEvent(TimeSpan timeout)
{
EventHandler<T> eventHandler = new EventHandler<T>((sender, args) => { _autoResetEvent.Set(); });
_event.AddEventHandler(_eventContainer, eventHandler);
_autoResetEvent.WaitOne(timeout);
_event.RemoveEventHandler(_eventContainer, eventHandler);
}
}
And for example I use that for waiting to get Url from HttpNotificationChannel when I registering to windows push notification service.
HttpNotificationChannel pushChannel = new HttpNotificationChannel(channelName);
//ChannelUriUpdated is event
EventWaiter<NotificationChannelUriEventArgs> ew = new EventWaiter<NotificationChannelUriEventArgs>(pushChannel, "ChannelUriUpdated");
pushChannel.Open();
ew.WaitForEvent(TimeSpan.FromSeconds(30));

Don't pass the event, pass a delegate that matches the event handler signature. This actually sounds hacky to me, so be aware of potential dead lock issues.

I've rushed together a working sample in LinqPad using reflection, getting a reference to the EventInfo object with a string (be careful as you loose compile time checking). The obvious issue is that there is no guarentee an event will ever be fired, or that the event your expecting may be fired before the EventWaiter class is ready to start blocking so I'm not sure I'd sleep comfy if I put this in a production app.
void Main()
{
Console.WriteLine( "main thread started" );
var workerClass = new WorkerClassWithEvent();
workerClass.PerformWork();
var waiter = new EventWaiter( workerClass, "WorkCompletedEvent" );
waiter.WaitForEvent( TimeSpan.FromSeconds( 10 ) );
Console.WriteLine( "main thread continues after waiting" );
}
public class WorkerClassWithEvent
{
public void PerformWork()
{
var worker = new BackgroundWorker();
worker.DoWork += ( s, e ) =>
{
Console.WriteLine( "threaded work started" );
Thread.Sleep( 1000 ); // <= the work
Console.WriteLine( "threaded work complete" );
};
worker.RunWorkerCompleted += ( s, e ) =>
{
FireWorkCompletedEvent();
Console.WriteLine( "work complete event fired" );
};
worker.RunWorkerAsync();
}
public event Action WorkCompletedEvent;
private void FireWorkCompletedEvent()
{
if ( WorkCompletedEvent != null ) WorkCompletedEvent();
}
}
public class EventWaiter
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent( false );
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter( object eventContainer, string eventName )
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent( eventName );
}
public void WaitForEvent( TimeSpan timeout )
{
_event.AddEventHandler( _eventContainer, (Action)delegate { _autoResetEvent.Set(); } );
_autoResetEvent.WaitOne( timeout );
}
}
Output
// main thread started
// threaded work started
// threaded work complete
// work complete event fired
// main thread continues after waiting

You may also try this:
class EventWaiter<TEventArgs> where TEventArgs : EventArgs
{
private readonly Action<EventHandler<TEventArgs>> _unsubHandler;
private readonly Action<EventHandler<TEventArgs>> _subHandler;
public EventWaiter(Action<EventHandler<TEventArgs>> subHandler, Action<EventHandler<TEventArgs>> unsubHandler)
{
_unsubHandler = unsubHandler;
_subHandler = subHandler;
}
protected void Handler(object sender, TEventArgs args)
{
_unsubHandler.Invoke(Handler);
TaskCompletionSource.SetResult(args);
}
public TEventArgs WaitOnce()
{
TaskCompletionSource = new TaskCompletionSource<TEventArgs>();
_subHandler.Invoke(Handler);
return TaskCompletionSource.Task.Result;
}
protected TaskCompletionSource<TEventArgs> TaskCompletionSource { get; set; }
}
Usage:
EventArgs eventArgs = new EventWaiter<EventArgs>((h) => { button.Click += new EventHandler(h); }, (h) => { button.Click -= new EventHandler(h); }).WaitOnce();

I think like these should work, didn't tried just coded.
public class EventWaiter<T> where T : EventArgs
{
private System.Threading.ManualResetEvent manualEvent;
public EventWaiter(T e)
{
manualEvent = new System.Threading.ManualResetEvent(false);
e += this.OnEvent;
}
public void OnEvent(object sender, EventArgs e)
{
manualEvent.Set();
}
public void WaitOne()
{
manualEvent.WaitOne();
}
public void Reset()
{
manualEvent.Reset();
}
}
Didn't thought about too much, but can't figure out how to make it isolated from the EventArgs.
Take a look at the MSDN ManualResetEvent and you will discover that you can kind of chain the waits and so some weird stuff.

Related

How to Wake up a sleeping thread?

I made a thread at load event like below:
Thread checkAlert = null;
bool isStop = false;
private void frmMain_Load(object sender, EventArgs e)
{
checkAlert = new Thread(CheckAlert);
checkAlert.Start();
}
void CheckAlert()
{
while (!isStop)
{
Thread.Sleep(60000);
//do work here
}
}
Is there any way to resume the checkAlert thread during it's sleep period?( Thread.Sleep(60000);)
I tried using Thread.Interrupt() but it flows a ThreadInterruptedException, how should I handle this exception? or is there any way to resume the thread?
Edited:
I need to wake up the thread before the "sleep" end because when the user wants to quit the program, the program will have to wait for some time before it really quits ( checkAlert is still running) Is there any way to improve this case?
Based on your comments what it looks like is you need to re-design how CheckAlert works so it does not use Sleep's at all. What you should be doing is using a Timer instead.
System.Timers.Timer timer = null;
public FrmMain()
{
InitializeComponent();
timer = new System.Timers.Timer(60000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
//If you want OnTimedEvent to happen on the UI thread instead of a ThreadPool thread, uncomment the following line.
//timer.SynchronizingObject = this;
if(this.components == null)
this.components = new System.ComponentModel.Container();
//This makes it so when the form is disposed the timer will be disposed with it.
this.componets.Add(timer);
}
private void frmMain_Load(object sender, EventArgs e)
{
timer.Start();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
//It is good practice not to do complicated logic in a event handler
// if we move the logic to its own method it is much easier to test (you are writing unit tests, right? ;) )
CheckAlert();
}
void CheckAlert()
{
//do work here
}
private void frmMain_Close(object sender, EventArgs e)
{
timer.Stop();
}
If you want the thread to exit automatically when your program quits, simply make it a background thread.
checkAlert = new Thread(CheckAlert);
checkAlert.IsBackground = true;
checkAlert.Start();
It looks to me like you're trying to create a thread which handles two types of events: do something and stop running.
Rather than using a shared variable (isStop) and some other technique to interrupt the thread in order to do work, you might want to use threading events (not to be confused high-level UI Event objects) to control your thread.
AutoResetEvent stop = new AutoResetEvent(false);
AutoResetEvent check = new AutoResetEvent(false);
private void CheckAlert() {
WaitHandle[] handles = new WaitHandle[] { stop, check };
for (;;) {
switch (AutoResetEvent.WaitAny(handles)) {
case 0:
return;
case 1:
// do work
break;
}
}
}
Calling check.Set() in your code will trigger the "do work" branch in the thread and stop.Set() will cause the thread to terminate gracefully.
Once your code has called stop.Set() to terminate the thread, it can call the thread's Join() method to wait until the thread terminates.
EDIT
I misunderstood the question. I will leave the code above in case anyone finds it useful.
If all you want to do is have a thread that performs a task once a minute and stop on demand, you can use the following code:
AutoResetEvent stop = new AutoResetEvent(false);
void CheckAlert() {
var time = new TimeSpan(0, 1, 0); // one minute
while (!stop.WaitOne(time)) {
// do work
}
}
private Thread checkThread;
private void frmMain_Load(object sender, EventArgs e) {
checkThread = new Thread(CheckAlert);
checkThread.Start();
}
private void frmMain_Close(object sender, EventArgs e) {
stop.Set(); // signal thread to stop
checkThread.Join(); // wait for thread to terminate
}
You can see an explanation on how to wake a sleeping thread here:
https://msdn.microsoft.com/en-us/library/tttdef8x%28v=vs.100%29.aspx
and this is a complete example (as you can see, Thread.Interrupt is the good choise... however you have to catch it to continue normal thread execution):
public class HVCSensor : HVCDevice, IDisposable
{
private Thread myThread;
private const int execute_timeout = ((10 + 10 + 6 + 3 + 15 + 15 + 1 + 1 + 15 + 10) * 1000);
private bool disposed = false;
private bool paused = false;
public delegate void HVCResultsHandler(HVC_RESULT res);
public event HVCResultsHandler HVCResultsArrived;
private void OnHVCResultsArrived(HVC_RESULT res)
{
if (HVCResultsArrived != null) {
HVCResultsArrived(res);
}
}
public HVCSensor() {
myThread = new Thread(new ThreadStart(this.execute));
}
private void execute(){
while (!disposed) {
if (!paused && this.IsConnected)
{
HVC_RESULT outRes;
byte status;
try
{
this.ExecuteEx(execute_timeout, activeDetections, imageAcquire, out outRes, out status);
OnHVCResultsArrived(outRes);
}
catch (Exception ex) {
}
}
else {
try
{
Thread.Sleep(1000);
}
catch (ThreadInterruptedException e)
{
}
}
}
}
public HVC_EXECUTION_IMAGE imageAcquire
{
get;
set;
}
public HVC_EXECUTION_FLAG activeDetections
{
get;
set;
}
public void startDetection() {
if(myThread.ThreadState==ThreadState.Unstarted)
myThread.Start();
}
public void pauseDetection() {
paused = true;
}
public void resumeDetection() {
paused = false;
if (myThread.ThreadState == ThreadState.WaitSleepJoin)
myThread.Interrupt();
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
disposed = true;
myThread.Interrupt();
}
}

Reusable class to wait for events to fire

I know this is slightly a duplicate of this question here: Blocking and waiting for an event
However, I was in the process of writing a EventWaiter and ran into a problem. Here is a (majorly) simplified version of what I've been working on:
public class EventWaiter
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter(object eventContainer, string eventName)
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent(eventName);
}
public void WaitForEvent()
{
MethodInfo method = this.GetType().GetMethod("DynamicCaller");
Delegate handler = Delegate.CreateDelegate(this._event.EventHandlerType, this, method);
_event.AddEventHandler(_eventContainer, handler);
_autoResetEvent.WaitOne();
_event.RemoveEventHandler(_eventContainer, _handler);
}
public void DynamicCaller(/* insert magic here */)
{
_autoResetEvent.Set();
}
}
The usage would simply be:
EventWaiter ew = new EventWaiter(someClass, "someEvent");
ew.WaitForEvent();
Basically what is happening, is its registering the DynamicCaller void as a handler for this event. The problem is, events have different signatures, and I want to be able to handle the event regardless of the delegate used.
I can get the type of the delegate with this._event.EventHandlerType but how can I use to that create a completely reusable class no matter what the delegate is? If the DynamicCaller parameters are not exactly the same as the event delegate parameters i get an exception.
As a side note, I did a bunch of looking into code in the framework, and if i had access to some of that I think this would be easy. Too bad that alot of the classes I would need are all internal to the framework.
Since all events that respect the recommended pattern have a parameter of type object and a parameter of a type that derives from EventArgs, you should be able to handle all these events with this signature:
void DynamicCaller(object sender, EventArgs e)
Of course it won't work for non-standard event signatures...
EDIT: here's an example with a dynamically generated handler:
public class EventWaiter
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter(object eventContainer, string eventName)
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent(eventName);
}
public void WaitForEvent()
{
Delegate handler = CreateHandler();
_event.AddEventHandler(_eventContainer, handler);
_autoResetEvent.WaitOne();
_event.RemoveEventHandler(_eventContainer, handler);
}
private Delegate CreateHandler()
{
var invokeMethod = _event.EventHandlerType.GetMethod("Invoke");
var invokeParameters = invokeMethod.GetParameters();
var handlerParameters = invokeParameters.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray();
var body = Expression.Call(Expression.Constant(_autoResetEvent), "Set", null);
var handlerExpression = Expression.Lambda(_event.EventHandlerType, body, handlerParameters);
return handlerExpression.Compile();
}
}
EDIT: SLaks was faster than me ;)
You should use expression trees to compile a method with an arbitrary set of parameters that calls your callback:
Expression.Lambda(
_event.EventHandlerType,
Expression.Call(Exrpession.Constant(_autoResetEvent),
typeof(AutoResetEvent).GetMethod("Set")),
_event.EventHandlerType.GetMethod("Invoke")
.GetParameters()
.Select(p => Expression.Parameter(p.ParameterType))
).Compile();
Note that you can make your system type-safe using generics and expression trees:
new EventWaiter(_ => someObject.SomeEvent += _)
Where _ is an ordinary (but short) parameter name.
You could do what you want with TaskCompletionSource:
TaskCompletionSource<string> tcs =
new TaskCompletionSource<string>();
WebClient client = new WebClient();
client.DownloadStringCompleted += (sender, args) => {
if (args.Error != null) tcs.SetException(args.Error);
else if (args.Cancelled) tcs.SetCanceled();
else tcs.SetResult(args.Result);
};
client.DownloadStringAsync(address);
tcs.Task.Wait(); // WaitForEvent
The solutions here are good, but for me, using strings, reflection has a bit of a code smell, so I'll go for a generic version:
public class EventWaiter
{
public enum Mode
{
Wait,
Detach
}
public static Func<Mode, TEventArgs> Create<TDelegate, TEventArgs>(
Func<Action<object, TEventArgs>, TDelegate> converter,
Action<TDelegate> addHandler,
Action<TDelegate> removeHandler
)
{
AutoResetEvent semaphore = new AutoResetEvent(false);
TEventArgs args = default(TEventArgs);
TDelegate handler = converter((s, e) => { args = e; semaphore.Set(); });
addHandler(handler);
return mode =>
{
if (mode == Mode.Wait)
{
semaphore.WaitOne();
return args;
}
else
{
removeHandler(handler);
return default(TEventArgs);
}
};
}
Usage:
var evt =
EventWaiter.Create<SerialDataReceivedEventHandler, SerialDataReceivedEventArgs>
(handler => (s, e) => handler(s, e),
h => port.DataReceived += h,
h => port.DataReceived -= h);
var firstArgument = evt(EventWaiter.Mode.Wait); //Wait for first event
var secondArgument = evt(EventWaiter.Mode.Wait); //Wait for second event
evt(EventWaiter.Mode.Detach); //Dispose

How to unit test this library?

I have an external library which has a method which performs a long running task on a background thread. When it's done it fires off a Completed event on the thread that kicked off the method (typically the UI thread). It looks like this:
public class Foo
{
public delegate void CompletedEventHandler(object sender, EventArgs e);
public event CompletedEventHandler Completed;
public void LongRunningTask()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(5000);
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (Completed != null)
Completed(this, EventArgs.Empty);
}
}
The code that calls this library looks like this:
private void button1_Click(object sender, EventArgs e)
{
Foo b = new Foo();
b.Completed += new Foo.CompletedEventHandler(b_Completed);
b.LongRunningTask();
Debug.WriteLine("It's all done");
}
void b_Completed(object sender, EventArgs e)
{
// do stuff
}
How do I unit test the call to .LongRunningTask given that it returns data in an event?
I'm not sure if I got it right. Do you want to check the external library if it fires the event? Or do you want to check that you do something particularly if the event is fired?
If it is the latter, I would use a mock for that. The problem is though, that your code seems to be hard to test, because you're doing logical stuff in the user interface. Try to write a "passive" view, and let a presenter do the magic. For example by using the Model View Presenter pattern http://msdn.microsoft.com/en-us/magazine/cc188690.aspx
The whole thing would then look like this.
The Model
public class Model : IModel
{
public event EventHandler<SampleEventArgs> Completed;
public void LongRunningTask()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += this.bw_DoWork;
bw.RunWorkerCompleted += this.bw_RunWorkerCompleted;
bw.RunWorkerAsync();
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (this.Completed != null)
{
this.Completed(this, new SampleEventArgs {Data = "Test"});
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(5000);
}
}
The View
public Form1()
{
InitializeComponent();
}
public event EventHandler Button1Clicked;
public void Update(string data)
{
this.label1.Text = data;
}
private void Button1Click(object sender, EventArgs e)
{
if (this.Button1Clicked != null)
{
this.Button1Clicked(this, EventArgs.Empty);
}
}
The Presenter
public class Presenter
{
private readonly IForm1 form1;
private readonly IModel model;
public Presenter(IForm1 form1, IModel model)
{
this.form1 = form1;
this.model = model;
this.form1.Button1Clicked += this.Form1Button1Clicked;
this.model.Completed += this.ModelCompleted;
}
private void ModelCompleted(object sender, SampleEventArgs e)
{
this.form1.Update(e.Data);
}
private void Form1Button1Clicked(object sender, EventArgs e)
{
this.model.LongRunningTask();
}
}
Somewhere you assemble it (e.g. in the Program class)
var form = new Form1();
var model = new Model();
var presenter = new Presenter(form, model);
Application.Run(form);
And then you can easily just test the presenter in an unit test. The part in the gui is now little enough to not be tested.
The possible test could look like this
[Test]
public void Test()
{
var form1Mock = new Mock<IForm1>();
var modelMock = new Mock<IModel>();
var presenter = new Presenter(form1Mock.Object, modelMock.Object);
modelMock.Setup(m => m.LongRunningTask()).Raises(m => m.Completed += null, new SampleEventArgs() { Data = "Some Data" });
form1Mock.Raise(f => f.Button1Clicked += null, EventArgs.Empty);
form1Mock.Verify(f => f.Update("Some Data"));
}
Well, I believe BackgroundWorker uses the current SynchronizationContext. You could potentially implement your own subclass of SynchronizationContext to allow you more control (possibly even running code on the same thread, although that will break anything which depends on it running in a different thread) and call SetSynchronizationContext before running the test.
You'd need to subscribe to the event in your test, and then check whether or not your handler was called. (Lambda expressions are good for this.)
For example, suppose you have a SynchronizationContext which lets you run all the work only when you want it to, and tell you when it's done, your test might:
Set the synchronization context
Create the component
Subscribe to the handler with a lambda which sets a local variable
Call LongRunningTask()
Verify that the local variable hasn't been set yet
Make the synchronization context do all its work... wait until it's finished (with a timeout)
Verify that the local variable has now been set
It's all a bit nasty, admittedly. If you can just test the work it's doing, synchronously, that would be a lot easier.
You can create an extension method that can help with turning it into a synchronous call. You can make tweaks like making it more generic and passing in the timeout variable but at least it will make the unit test easier to write.
static class FooExtensions
{
public static SomeData WaitOn(this Foo foo, Action<Foo> action)
{
SomeData result = null;
var wait = new AutoResetEvent(false);
foo.Completed += (s, e) =>
{
result = e.Data; // I assume this is how you get the data?
wait.Set();
};
action(foo);
if (!wait.WaitOne(5000)) // or whatever would be a good timeout
{
throw new TimeoutException();
}
return result;
}
}
public void TestMethod()
{
var foo = new Foo();
SomeData data = foo.WaitOn(f => f.LongRunningTask());
}
For testing asynchronous code I use a similar helper:
public class AsyncTestHelper
{
public delegate bool TestDelegate();
public static bool AssertOrTimeout(TestDelegate predicate, TimeSpan timeout)
{
var start = DateTime.Now;
var now = DateTime.Now;
bool result = false;
while (!result && (now - start) <= timeout)
{
Thread.Sleep(50);
now = DateTime.Now;
result = predicate.Invoke();
}
return result;
}
}
In the test method then call something like this:
Assert.IsTrue(AsyncTestHelper.AssertOrTimeout(() => changeThisVarInCodeRegisteredToCompletedEvent, TimeSpan.FromMilliseconds(500)));

C# Threading Mechanism

Let's say I have an exposed interface as such:
interface IMyService
{
MyResult MyOperation();
}
This operation is synchronous and returns a value.
My implemented interface has to do the following:
Call an asynchronous method
Wait for event #1
Wait for event #2
This is due to a 3rd party COM object I am working with.
This code looks similar to the following
public MyResult MyOperation()
{
_myCOMObject.AsyncOperation();
//Here I need to wait for both events to fire before returning
}
private void MyEvent1()
{
//My Event 1 is fired in this handler
}
private void MyEvent2()
{
//My Event 2 is fired in this handler
}
My two events can happen in either order, it is quite random.
What is the proper threading mechanism I can use to synchronize this? I was using ManualResetEvent before I had to start waiting for the second event, and have not seen an easy way to use it for both events. These 2 events set variables that allow me to create the return value for MyOperation().
Any ideas on a good implementation for this? I have no control over the way the 3rd party object is implemented.
Two ManualResetEvents should do the trick for you. Just initialize them to false before you call the _myCOMObject.AsyncOperation(). Like this:
private ManualResetEvent event1;
private ManualResetEvent event2;
public MyResult MyOperation()
{
event1 = new ManualResetEvent(false);
event2 = new ManualResetEvent(false);
_myCOMObject.AsyncOperation();
WaitHandle.WaitAll(new WaitHandle[] { event1, event2 });
}
private void MyEvent1()
{
event1.Set();
}
private void MyEvent2()
{
event2.Set();
}
Edit
Thanks for the comments. I've changed the wait call to use WaitAll
My implementation example is as follows:
namespace ConsoleApplication1
{
class Program
{
private static WaitHandle[] waitHandles;
private static event EventHandler Evt1;
private static event EventHandler Evt2;
static void Main(string[] args)
{
waitHandles = new WaitHandle[]{
new ManualResetEvent(false),
new ManualResetEvent(false)
};
Evt1 += new EventHandler(Program_Evt1);
Evt2 += new EventHandler(Program_Evt2);
OnEvt1();
OnEvt2();
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("Finished");
Console.ReadLine();
}
static void Program_Evt2(object sender, EventArgs e)
{
Thread.Sleep(2000);
((ManualResetEvent)waitHandles[0]).Set();
}
static void Program_Evt1(object sender, EventArgs e)
{
((ManualResetEvent)waitHandles[1]).Set();
}
static void OnEvt1()
{
if (Evt1 != null)
Evt1(null, EventArgs.Empty);
}
static void OnEvt2()
{
if (Evt2 != null)
Evt2(null, EventArgs.Empty);
}
}
}
I make it sleep for the purposes of this example and the WaitAll functionality
Cheers,
Andrew
P.S. another example would be using AsyncCallback, really quick and dirty example, but gives you more keys to open the door with :-) . Hope this helps!!
namespace ConsoleApplication1
{
class Program
{
private static WaitHandle[] waitHandles;
private static event EventHandler Evt1;
private static event EventHandler Evt2;
static void Main(string[] args)
{
waitHandles = new WaitHandle[]{
new ManualResetEvent(false),
new ManualResetEvent(false)
};
var callabck1 = new AsyncCallback(OnEvt1);
var callabck2 = new AsyncCallback(OnEvt2);
callabck1.Invoke(new ManualResetResult(null, (ManualResetEvent)waitHandles[0]));
callabck2.Invoke(new ManualResetResult(null, (ManualResetEvent)waitHandles[1]));
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("Finished");
Console.ReadLine();
}
static void OnEvt1(IAsyncResult result)
{
Console.WriteLine("Setting1");
var handle = result.AsyncWaitHandle;
((ManualResetEvent)handle).Set();
}
static void OnEvt2(IAsyncResult result)
{
Thread.Sleep(2000);
Console.WriteLine("Setting2");
var handle = result.AsyncWaitHandle;
((ManualResetEvent)handle).Set();
}
}
public class ManualResetResult : IAsyncResult
{
private object _state;
private ManualResetEvent _handle;
public ManualResetResult(object state, ManualResetEvent handle)
{
_state = state;
_handle = handle;
}
#region IAsyncResult Members
public object AsyncState
{
get { return _state; }
}
public WaitHandle AsyncWaitHandle
{
get { return _handle; }
}
public bool CompletedSynchronously
{
get { throw new NotImplementedException(); }
}
public bool IsCompleted
{
get { throw new NotImplementedException(); }
}
#endregion
}
}
I am not sure I understood your question, but AutoResetEvent.WaitAll seems to solve your problem, if I got it right. It allows you to set more than one handler and it will only be released when all are set.
http://msdn.microsoft.com/en-us/library/z6w25xa6.aspx

How do I make event callbacks into my win forms thread safe?

When you subscribe to an event on an object from within a form, you are essentially handing over control of your callback method to the event source. You have no idea whether that event source will choose to trigger the event on a different thread.
The problem is that when the callback is invoked, you cannot assume that you can make update controls on your form because sometimes those controls will throw an exception if the event callback was called on a thread different than the thread the form was run on.
To simplify Simon's code a bit, you could use the built in generic Action delegate. It saves peppering your code with a bunch of delegate types you don't really need. Also, in .NET 3.5 they added a params parameter to the Invoke method so you don't have to define a temporary array.
void SomethingHappened(object sender, EventArgs ea)
{
if (InvokeRequired)
{
Invoke(new Action<object, EventArgs>(SomethingHappened), sender, ea);
return;
}
textBox1.Text = "Something happened";
}
Here are the salient points:
You can't make UI control calls from a different thread than the one they were created on (the form's thread).
Delegate invocations (ie, event hooks) are triggered on the same thread as the object that is firing the event.
So, if you have a separate "engine" thread doing some work and have some UI watching for state changes which can be reflected in the UI (such as a progress bar or whatever), you have a problem. The engine fire's an object changed event which has been hooked by the Form. But the callback delegate that the Form registered with the engine gets called on the engine's thread… not on the Form's thread. And so you can't update any controls from that callback. Doh!
BeginInvoke comes to the rescue. Just use this simple coding model in all your callback methods and you can be sure that things are going to be okay:
private delegate void EventArgsDelegate(object sender, EventArgs ea);
void SomethingHappened(object sender, EventArgs ea)
{
//
// Make sure this callback is on the correct thread
//
if (this.InvokeRequired)
{
this.Invoke(new EventArgsDelegate(SomethingHappened), new object[] { sender, ea });
return;
}
//
// Do something with the event such as update a control
//
textBox1.Text = "Something happened";
}
It's quite simple really.
Use InvokeRequired to find out if this callback happened on the correct thread.
If not, then reinvoke the callback on the correct thread with the same parameters. You can reinvoke a method by using the Invoke (blocking) or BeginInvoke (non-blocking) methods.
The next time the function is called, InvokeRequired returns false because we are now on the correct thread and everybody is happy.
This is a very compact way of addressing this problem and making your Forms safe from multi-threaded event callbacks.
I use anonymous methods a lot in this scenario:
void SomethingHappened(object sender, EventArgs ea)
{
MethodInvoker del = delegate{ textBox1.Text = "Something happened"; };
InvokeRequired ? Invoke( del ) : del();
}
I'm a bit late to this topic, but you might want to take a look at the Event-Based Asynchronous Pattern. When implemented properly, it guarantees that events are always raised from the UI thread.
Here's a brief example that only allows one concurrent invocation; supporting multiple invocations/events requires a little bit more plumbing.
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class MainForm : Form
{
private TypeWithAsync _type;
[STAThread()]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new MainForm());
}
public MainForm()
{
_type = new TypeWithAsync();
_type.DoSomethingCompleted += DoSomethingCompleted;
var panel = new FlowLayoutPanel() { Dock = DockStyle.Fill };
var btn = new Button() { Text = "Synchronous" };
btn.Click += SyncClick;
panel.Controls.Add(btn);
btn = new Button { Text = "Asynchronous" };
btn.Click += AsyncClick;
panel.Controls.Add(btn);
Controls.Add(panel);
}
private void SyncClick(object sender, EventArgs e)
{
int value = _type.DoSomething();
MessageBox.Show(string.Format("DoSomething() returned {0}.", value));
}
private void AsyncClick(object sender, EventArgs e)
{
_type.DoSomethingAsync();
}
private void DoSomethingCompleted(object sender, DoSomethingCompletedEventArgs e)
{
MessageBox.Show(string.Format("DoSomethingAsync() returned {0}.", e.Value));
}
}
class TypeWithAsync
{
private AsyncOperation _operation;
// synchronous version of method
public int DoSomething()
{
Thread.Sleep(5000);
return 27;
}
// async version of method
public void DoSomethingAsync()
{
if (_operation != null)
{
throw new InvalidOperationException("An async operation is already running.");
}
_operation = AsyncOperationManager.CreateOperation(null);
ThreadPool.QueueUserWorkItem(DoSomethingAsyncCore);
}
// wrapper used by async method to call sync version of method, matches WaitCallback so it
// can be queued by the thread pool
private void DoSomethingAsyncCore(object state)
{
int returnValue = DoSomething();
var e = new DoSomethingCompletedEventArgs(returnValue);
_operation.PostOperationCompleted(RaiseDoSomethingCompleted, e);
}
// wrapper used so async method can raise the event; matches SendOrPostCallback
private void RaiseDoSomethingCompleted(object args)
{
OnDoSomethingCompleted((DoSomethingCompletedEventArgs)args);
}
private void OnDoSomethingCompleted(DoSomethingCompletedEventArgs e)
{
var handler = DoSomethingCompleted;
if (handler != null) { handler(this, e); }
}
public EventHandler<DoSomethingCompletedEventArgs> DoSomethingCompleted;
}
public class DoSomethingCompletedEventArgs : EventArgs
{
private int _value;
public DoSomethingCompletedEventArgs(int value)
: base()
{
_value = value;
}
public int Value
{
get { return _value; }
}
}
}
As the lazy programmer, I have a very lazy method of doing this.
What I do is simply this.
private void DoInvoke(MethodInvoker del) {
if (InvokeRequired) {
Invoke(del);
} else {
del();
}
}
//example of how to call it
private void tUpdateLabel(ToolStripStatusLabel lbl, String val) {
DoInvoke(delegate { lbl.Text = val; });
}
You could inline the DoInvoke inside your function or hide it within separate function to do the dirty work for you.
Just keep in mind you can pass functions directly into the DoInvoke method.
private void directPass() {
DoInvoke(this.directInvoke);
}
private void directInvoke() {
textLabel.Text = "Directly passed.";
}
In many simple cases, you can use the MethodInvoker delegate and avoid the need to create your own delegate type.

Categories