I need to raise an event without blocking the calling method, what is the way to do it?
1) Start a task and raise the event from within the task? :
//Body of listener function above
if (EventFound)
Task.Factory.StartNew(() =>
{
SendEvent();
});
2) Start a task from within the eventhandler:
public void OnEventRaised(....)
{
Task.Factory.StartNew(() =>
{
//Do lengthy stuff here
});
}
Does either block the calling function?
Neither of your examples blocks the caller.
In your first example the caller creates a new thread and invokes all subscribers sequentially (if there are more than one). In the second option the subscriber creates a thread, so each one will have it's own thread.
Please keep in mind that both options will crash the application if any of the event handlers fail.
You can get more relevant information from here: Raising events asynchronously
You can use Async Await keywords
http://www.codeproject.com/Tips/591586/Asynchronous-Programming-in-Csharp-using-async
Related
I am trying to post a lean question here, without code, because my question is so specific: Is it possible/acceptable to modify the SynchronizationContext within an Async method? If I don't set SynchronizationContext when the Async method begins, it seems that code within it--including events I raise and methods within the same class module I call--run on the same worker thread. However, when it comes time to interact with the UI, I find that the SynchronizationContext has to be set to the UI thread.
Is it okay to keep the SynchronizationContext set to the worker thread until such time that I want to invoke a call to a UI-based function?
EDIT:
To further clarify my above question, I find myself in a no-win situation with respect to the SynchronizationContext setting. If don't set the SynchronizationContext then my async operations run on a separate thread (as desired) but then I can't return data to the UI thread without encountering a cross-thread operation exception; if I set the SynchronizationContext to my UI thread then the operations I want to run on a separate thread end up running on the UI thread--and then (of course) I avoid the cross-thread exception and everything works. Clearly, I'm missing something.
If you care to read more, I've tried to provide a very clear explanation of what I'm trying to do and I realize you're investing your time to understand so thank you for that!
What I'm trying to do is shown in this flow diagram:
I have a Winforms application running on the UI thread (in black); I have a Socket object I'd like to run on its own thread. The job of the socket class is to read data from a communication socket and raise events back to the UI whenever data arrives.
Note that I start a message loop from the UI thread so that the socket is continually polled for data on its own thread; if data is received, I want to process that data synchronously on the same non-UI thread before grabbing any more data from the socket. (Yes, if something goes awry with any particular socket read, the socket might be left with unread data in it.)
The code to start the message loop looks like this:
if (Socket.IsConnected)
{
SetUpEventListeners();
// IMPORTANT: next line seems to be required in order to avoid a cross-thread error
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
Socket.StartMessageLoopAsync();
}
When I start the message loop from the UI thread, I call an async method on the Socket object:
public async void StartMessageLoopAsync()
{
while (true)
{
// read socket data asynchronously and populate the global DataBuffer
await ReadDataAsync();
if (DataBuffer.Count == 0)
{
OnDataReceived();
}
}
}
The Socket object also has the OnDataReceived() method defined as:
protected void OnDataReceived()
{
var dataEventArgs = new DataEventArgs();
dataEventArgs.DataBuffer = DataBuffer;
// *** cross-thread risk here!
DataReceived?.Invoke(this, dataEventArgs);
}
I have highlighted two areas of the diagram with "1" and "2" blue stars.
In "1" (on the diagram), I am using the async/await pattern. I am using a third-party socket tool that doesn't support Async, so I have wrapped that in my own ReadDataAsync() function that looks like this:
public override async Task ReadDataAsync()
{
// read a data asynchronously
var task = Task.Run(() => ReadData());
await task;
}
ReadData() wraps the third-party component's read method: it populates a global data buffer, so no return value is needed.
In "2" in the diagram, I am encountering the cross-thread risk described in my OnDataReceived() method cited above.
Bottom Line: If I set SynchronizationContext as shown in my first code clip above, then everything in the Socket object runs on its own thread until I try to invoke the DataReceived event handler; if I comment-out the SynchronizationContext then the only part of the code that runs on its own thread is the brief third-party socket-read operation wrapped in my DataReadAsync() method.
So my thought was whether I can set the SynchronizationContext just ahead of trying to invoke the DataReceived event handler. And even if I "can", the better question is whether this is a good idea. If I do modify SynchronizationContext within the non-UI thread then I'd have to set it back to its original value after invoking the DataReceived method, and that has a Durian-like code-smell to me.
Is there an elegant tweak to my design or does it need an overhaul? My goal is to have all red items in the diagram running on a non-UI thread and the black items running on the UI thread. "2" is the point at which the non-UI thread my cross over to the UI thread...
Thank you.
Setting context directly isn't the best idea since other functionality being occasionally executed in this thread can be affected. The most natural way to control synchronization context for async/await flows is using ConfigureAwait. So in your case I see two options to achieve what you want:
1) Use ConfigureAwait(false) with ReadDataAsync
public async void StartMessageLoopAsync()
{
while (true)
{
// read socket data asynchronously and populate the global DataBuffer
await ReadDataAsync().ConfigureAwait(false);
if (DataBuffer.Count == 0)
{
OnDataReceived();
}
}
}
which will make resuming everything after await in background thread. And then use Dispatcher Invoke to marshal DataReceived?.Invoke into UI thread:
protected void OnDataReceived()
{
var dataEventArgs = new DataEventArgs();
dataEventArgs.DataBuffer = DataBuffer;
// *** cross-thread risk here!
Dispatcher.CurrentDispathcer.Invoke(() => { DataReceived?.Invoke(this, dataEventArgs ); });
}
Or 2) Make some logic decomposition like as follows:
public async void StartMessageLoopAsync()
{
while (true)
{
// read socket data asynchronously and populate the global DataBuffer
await ProcessDataAsync();
// this is going to run in UI thread but there is only DataReceived invocation
if (DataBuffer.Count == 0)
{
OnDataReceived();
}
}
}
OnDataReceived is thin now and does only event triggering
protected void OnDataReceived()
{
// *** cross-thread risk here!
DataReceived?.Invoke(this, dataEventArgs);
}
This consolidates the functionality supposed to run in background thread
private async Task ProcessDataAsync()
{
await ReadDataAsync().ConfigureAwait(false);
// this is going to run in background thread
var dataEventArgs = new DataEventArgs();
dataEventArgs.DataBuffer = DataBuffer;
}
public override async Task ReadDataAsync()
{
// read a data asynchronously
var task = Task.Run(() => ReadData());
await task;
}
This seems like a scenario better served with reactive extensions:
Reactive Extensions for .NET
What I'm trying to do is perform a heavy task triggered by a button event on the MainWindow, but still be able to drag the window freely. I've tried both the async/await pattern and creating new threads. However, threads will be nonblocking, MainWindow still freezes. Here's the code:
uiTIN.Click += async (o, e) =>
{
var _ = await Task.Run(() => job());
};
That's the button callback and here is the func:
private int job()
{
this.Dispatcher.Invoke(() =>
{
//Other function calls here omitted
});
return 0;
}
EDIT: The workaround was to use BackgroundWorker and I have also decorated dependent UI code snippets in Dispatcher Invoke function
From Microsoft's doccumentation on Dispatcher (emphasis mine):
In WPF, a DispatcherObject can only be accessed by the Dispatcher it is associated with. For example, a background thread cannot update the contents of a Button that is associated with the Dispatcher on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvoke. Invoke is synchronous and BeginInvoke is asynchronous. The operation is added to the queue of the Dispatcher at the specified DispatcherPriority.
So basically what you're doing is call an asynchronous method, and then forcing it to run on the UI thread, which accomplishes nothing.
In your //Other function calls here omitted, I'm asuming that you need to access some part of the UI, if that's not the case, all you have to do is remove the Dispatcher.Invoke from your method.
If my assumptions are right, then you must figure out a way of splitting your function, so that the part that isn't UI related run in a Background thread and only what needs to run on the UI Thread actually do.
My suggestion is to use a Background Worker. Here's how it'd look:
uiTIN.Click += (o, e) =>
{
job();
};
... and then ...
private int job()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
// Part of other function calls here omitted that don't need to run on the UI thread
Dispatcher.Invoke(() =>
{
// Part of other function calls here omitted that must run on the UI thread
});
};
worker.RunWorkerAsync();
return 0;
}
The normal practice is that you have to return from buttons onClick event callback as soon as you can in order to avoid blocking the main thread(or some refer to UI thread). If the main thread is blocked the application will look like frozen. This is a fundamental design of any GUI application to synchronize UI flow.
You start an async task in callback but you also wait for the task to finish before returning. You should start a BackgroundWorker in the onClick event then return.
It has been explained quite well already why your code was blocking the UI thread (queuing your work on the Dispatcher). But I would not recommend the usage of the BackgroundWorker, I would rather fix your code with Task.Run for several reasons all explained in this article: https://blog.stephencleary.com/2013/09/taskrun-vs-backgroundworker-conclusion.html
Consider two classes; Producer and Consumer (the same as classical pattern, each with their own threads). Is it possible for Producer to have an Event which Consumer can register to and when the producer triggers the event, the consumer's event handler is run in its own thread? Here are my assumptions:
Consumer does not know if the Producer's event is triggered
within his own thread or another.
Neither Producer nor Consumer are descendants of Control so they don't have
BeginInvoke method inherited.
PS. I'm not trying to implement Producer - Consumer pattern. These are two simple classes which I'm trying to refactor the producer so it incorporates threads.
[UPDATE]
To further expand my problem, I'm trying to wrap a hardware driver to be worked with in the simplest way possible. For instance my wrapper will have a StateChanged event which the main application will register to so it will be notified when hardware is disconnected. As the actual driver has no means other than polling to check its presence , I will need to start a thread to check it periodically. Once it is not available anymore I will trigger the event which needs to be executed in the same thread as it was added. I know this is a classical Producer-Consumer pattern but since I'm trying to simplify using my driver-wrapper, I don't want the user code to implement consumer.
[UPDATE]
Due to some comments suggesting that there's no solution to this problem, I would like to add few lines which might change their minds. Considering the BeginInvoke can do what I want, so it shouldn't be impossible (at least in theory). Implementing my own BeginInvoke and calling it within the Producer is one way to look at it. It's just that I don't know how BeginInvoke does it!
You want to do inter thread communication. Yes it is possible.
Use System.Windows.Threading.Dispatcher
http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx
The Dispatcher maintains a prioritized queue of work items for a specific thread.
When a Dispatcher is created on a thread, it becomes the only Dispatcher that can be associated with the thread, even if the Dispatcher is shut down.
If you attempt to get the CurrentDispatcher for the current thread and a Dispatcher is not associated with the thread, a Dispatcher will be created. A Dispatcher is also created when you create a DispatcherObject. If you create a Dispatcher on a background thread, be sure to shut down the dispatcher before exiting the thread.
Yes there is a way to do this. It relies on using the SynchronizationContext class (docs). The sync context abstracts the operations of sending messages from one thread to another via the methods Send (synchronous for the calling thread) and Post(async for the calling thread).
Let's take a slightly simpler situation where you only want the capture one sync context, the context of the "creator" thread. You would do something like this:
using System.Threading;
class HardwareEvents
{
private SynchronizationContext context;
private Timer timer;
public HardwareEvents()
{
context = SynchronizationContext.Current ?? new SynchronizationContext();
timer = new Timer(TimerMethod, null, 0, 1000); // start immediately, 1 sec interval.
}
private void TimerMethod(object state)
{
bool hardwareStateChanged = GetHardwareState();
if (hardwareStateChanged)
context.Post(s => StateChanged(this, EventArgs.Empty), null);
}
public event EventHandler StateChanged;
private bool GetHardwareState()
{
// do something to get the state here.
return true;
}
}
Now, the creating thread's sync context will be used when events are invoked. If the creating thread was a UI thread it will have a sync context supplied by the framework. If there is no sync context, then the default implementation is used, which invokes on the thread pool. SynchronizationContext is a class that you can subclass if you want to provide a custom way to send a message from the producer to the consumer thread. Just override Post and Send to send said message.
If you wanted every event subscriber to get called back on their own thread, you would have to capture the sync context in the add method. You then hold on to pairs of sync contexts and delegates. Then when raising the event, you would loop through the sync context / delegate pairs and Post each one in turn.
There are several other ways you could improve this. For example, you may want to suspend polling the hardware if there no subscribers to the event. Or you might want to back off your polling frequency if the hardware does not respond.
First, please note that in .NET / the Base Class Library, it is usually the event subscriber's obligation to ensure that its callback code is executing on the correct thread. That makes it easy for the event producer: it may just trigger its event without having to care about any thread affinities of its various subscribers.
Here's a complete example step-by-step of a possible implementation.
Let's start with something simple: The Producer class and its event, Event. My example won't include how and when this event gets triggered:
class Producer
{
public event EventHandler Event; // raised e.g. with `Event(this, EventArgs.Empty);`
}
Next, we want to be able to subscribe our Consumer instances to this event and be called back on a specific thread (I'll call this kind of thread a "worker thread"):
class Consumer
{
public void SubscribeToEventOf(Producer producer, WorkerThread targetWorkerThread) {…}
}
How do we implement this?
First, we need the means to "send" code to a specific worker thread. Since there is no way to force a thread to execute a particular method whenever you want it to, you must arrange for a worker thread to explicitly wait for work items. One way to do this is via a work item queue. Here's a possible implementation for WorkerThread:
sealed class WorkerThread
{
public WorkerThread()
{
this.workItems = new Queue<Action>();
this.workItemAvailable = new AutoResetEvent(initialState: false);
new Thread(ProcessWorkItems) { IsBackground = true }.Start();
}
readonly Queue<Action> workItems;
readonly AutoResetEvent workItemAvailable;
public void QueueWorkItem(Action workItem)
{
lock (workItems) // this is not extensively tested btw.
{
workItems.Enqueue(workItem);
}
workItemAvailable.Set();
}
void ProcessWorkItems()
{
for (;;)
{
workItemAvailable.WaitOne();
Action workItem;
lock (workItems) // dito, not extensively tested.
{
workItem = workItems.Dequeue();
if (workItems.Count > 0) workItemAvailable.Set();
}
workItem.Invoke();
}
}
}
This class basically starts a thread, and puts it in an infinite loop that falls asleep (WaitOne) until an item arrives in its queue (workItems). Once that happens, the item — an Action — is dequeued and invoked. Then the thread goes to sleep again (WaitOne)) until another item is available in the queue.
Actions are put in the queue via the QueueWorkItem method. So essentially we can now send code to be executed to a specific WorkerThread instance by calling that method. We're now ready to implement Customer.SubscribeToEventOf:
class Consumer
{
public void SubscribeToEventOf(Producer producer, WorkerThread targetWorkerThread)
{
producer.Event += delegate(object sender, EventArgs e)
{
targetWorkerThread.QueueWorkItem(() => OnEvent(sender, e));
};
}
protected virtual void OnEvent(object sender, EventArgs e)
{
// this code is executed on the worker thread(s) passed to `Subscribe…`.
}
}
Voilà!
P.S. (not discussed in detail): As an add-on, you could package the method of sending code to WorkerThread using a standard .NET mechanism called a SynchronizationContext:
sealed class WorkerThreadSynchronizationContext : SynchronizationContext
{
public WorkerThreadSynchronizationContext(WorkerThread workerThread)
{
this.workerThread = workerThread;
}
private readonly WorkerThread workerThread;
public override void Post(SendOrPostCallback d, object state)
{
workerThread.QueueWorkItem(() => d(state));
}
// other overrides for `Send` etc. omitted
}
And at the beginning of WorkerThread.ProcessWorkItems, you'd set the synchronization context for that particular thread as follows:
SynchronizationContext.SetSynchronizationContext(
new WorkerThreadSynchronizationContext(this));
I posted earlier that I've been there, and that there is no nice solution.
However, I just stumbled upon something I have done in another context before: you could instantiate a timer (that is, Windows.Forms.Timer) when you create your wrapper object. This timer will post all Tick events to the ui thread.
Now if you're device polling logic is non-blocking and fast, you could implement it directly inside the timer Tick event, and raise your custom event there.
Otherwise, you could continue to do the polling logic inside a thread, and instead of firing the event inside the thread, you just flip some boolean variable which gets read by the timer every 10 ms, who then fires the event.
Note that this solution still requires that the object is created from the GUI thread, but at least the user of the object will not have to worry about Invoke.
It is possible. One typical approach is to use the BlockingCollection class. This data structure works like a normal queue except that the dequeue operation blocks the calling thread if the queue is empty. The produce will queue items by calling Add and the consumer will dequeue them by calling Take. The consumer typically runs it's own dedicated thread spinning an infinite loop waiting for items to appear in the queue. This is, more or less, how the message loop on the UI thread operates and is the basis for getting the Invoke and BeginInvoke operations to accomplish the marshaling behavior.
public class Consumer
{
private BlockingCollection<Action> queue = new BlockingCollection<Action>();
public Consumer()
{
var thread = new Thread(
() =>
{
while (true)
{
Action method = queue.Take();
method();
}
});
thread.Start();
}
public void BeginInvoke(Action method)
{
queue.Add(item);
}
}
I am working on a Winform Application. The Method is started by a BackgroundWorker Thread. I am sorry. I did not mention this earlier.
private void Method()
{
tasks[i] = Task.Factory
.StartNew(() => fileProcessor.ProcessEachMachine(mdetail))
.ContinueWith(UpdateLabel, TaskContinuationOptions.OnlyOnRanToCompletion);
}
I have a long running function ProcessEachMachine. In the continuation function UpdateLabel I want to access UIlabel and update the status.
private void UpdateLabel()
{
progressLbl.Text = "updated";
}
But the label is not getting updated. How to access UILabel and update the text of it.?
You have to set the TaskScheduler.FromCurrentSynchronizationContext on ContinueWith or else it will not be run in the UI context. Here is the MSDN on the override that you must use for this call to ContinueWith.
It should end up looking like this:
.ContinueWith(UpdateLabel, null,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
It may seem like nothing is happening, but the TPL is currently swallowing your cross thread exception. You should probably use the UnobservedTaskException if you are not going to inspect each result or check for its exception. Otherwise, when garbage collection occurs, the exception will happen then...which could create hard to debug errors.
UPDATE
Based on your update about the main Task being setup and started by a Backgroundworker, my main question is why this could not use a Task to start? In fact, if there is not more in the Method, then this is really just double work and might confuse other developers. You are already started asynchronously, so why not just do your work within the backgroundworker and use an OnComplete method that will UpdateLabel (as background workers are already context aware).
The main problem is still the same though, so here are some other solutions if you feel you must use the TPL:
You can Invoke back onto the main UI thread within the UpdateLabel method
You can pass the current context into the backgroundworker and use that instead
You can Wait for your original Task to return and then use the worker's oncomplete event to update the label.
Here is how I would do this (all pseudo code)
Background Worker Method:
Method() called because of Background worker
private void Method()
{
fileProcessor.ProcessEachMachine(mdetail);
}
Wire up background worker's OnRunWorkerCompleted:
if(!e.Cancelled && !e.Error)
UpdateLabel();
Task only method
Call Method() from the main thread and just let the TPL do its work :)
Task.Factory.StartNew(() => fileProcessor.ProcessEachMachine(mdetail))
.ContinueWith((precedingTask)=>{if(!precedingTask.Error)UpdateLabel;},
null, TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
Is there an elegant way to know when a worker thread is done executing so I can access resources it produced?
For example if the worker thread queried a list of SQL Servers using
ServersSqlDataSourceEnumerator.Instance.GetDataSources();
and saved the result in a DataTable variable, what mechanism can I use to know when this DataTable variable has been populated/is available. I don't want to poll ThreadState; it would be ideal to fire an event when it's done so I can perform actions with the result.
Thanks!
You can use a callback mechanism or block on an event to know of completion of an Async operation. See this page for the Asychronous Programming Model in .net - you can call BeginInvoke on any delegate to perform the action in an Async manner.
If you're using the BackgroundWorker type, you can subscribe to the RunWorkerCompleted event.
So fire an event :-P
You could also look at using an AutoResetEvent:
http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx
What I do in this instance is get the WorkerThread to call a function after it has completed the work, which will invoke the the UI Thread, which can do the work in which you require.
E.g.
private void SetWorkerThreadToDoWork()
{
WorkerThread.Start();
}
private void MyWorkerThreadWork()
{
//This will be on the WorkerThread (called from WorkerThread.Start())
DoWorkFunc();
WorkComplete();
}
private void WorkComplete()
{
if(InvokeRequired == true)
{
//Do the invoke
}
else
{
//Check work done by worker thread
//e.g. ServersSqlDataSourceEnumerator.Instance.GetDataSources();
}
}
If it's a simple process you're using, I'd go for a BackgroundWorkerThread, this comes with it's own events that are fired when work is complete. But if you require to use a Thread, I would either look in to Asynchronous Callbacks or a similar route to that shown above.
You can check my answer on this SO thread
It uses a call back mechanism. When the async operation is done, it will fire the callback method where you can handle the processing that needs to be done post SQL execution.
Use a similar approach to be notified when the asynchronous operation is done.
Hope this helps :)
I don't program in C# but here's what I did with Delphi, maybe you can do it as well with C#.
I have a TThread descendant, and in the "destroy" event I send a message to its creator saying "hey I'm about to die !".
This way its parent (which is the main thread) creates a new one if it needs a new one. To be precise it launches a timer that, when fired, creates a new thread if a new one is needed (sites sucking time (lol) !!).