I assume that I can just call
var dispatcherOp = Application.Current.Dispatcher.BeginInvoke(Action());
dispatcherOp.Completed += dispatcherOp_Completed;
but then I am a little concerned. If begininvoke is asynchronous, then What prevents the dispatcher from completing the action before I get the returned dispatcher operation and attach to the completed event.
i assume that this must be impossible, but if so, I would like to know why.
You are correct; this is not safe. You should simply await the operation.
The answer is: nothing.
There are three possible approaches:
1.) You can decide that it is not important to wait for the operation to be executed. If so, then you are choosing the fire and forget strategy.
2.) You can decide that you want a synchronous request, so you await, like SLaks suggested.
3.) You can keep the request to be asynchronous, but use a callback.
Unfortunately Dispatcher does not have a callback function it takes for begininvoke.
Synchronous operation is not desired in my program, but I realized after a google search or two that I can lock on it like this
lock (this)
{
var dispatcherOp = Application.Current.Dispatcher.BeginInvoke(MyAction, DispatcherPriority.Normal);
dispatcherOp.Completed += dispatcherOp_Completed;
}
void dispatcherOp_Completed(object sender, EventArgs e)
{
lock (this)
{
}
}
and then lock again on the same object in the completed function so that the dispatcher can't complete till you have finished attaching your handler.
There is never a reason to use Dispatcher.BeginInvoke in a modern application.
If your code models a background operation, then use async/await, with IProgress<T> for any progress updates.
If your code models an asynchronous sequence, then use Rx (Reactive Extensions) with ObserveOn to update objects with UI thread affinity.
Related
In doing my research here there seem to be about a million different ways to accomplish this, but the pros and cons of each are less unclear. One possibility that seems to accomplish what I'm after is:
private async Task SomeMostlyUIMethod(byte[] someParam = null)
{
if (InvokeRequired)
{
Task result = Task.Run(() => Invoke((Action)(async () => await SomeMostlyUIMethod(someParam))));
await result;
return;
}
else
{
// do some stuff
}
}
That seems to work, it feels like there should be a more clear solution for this. I'm not invoking on a per control modified basis because the method modifies a large number of different UI components, but also need to keep the method asynchronous since it has some expensive non-ui tasks it carries out as well.
to make work item will be executed on UI thread, you probably need the current synchronization context:
factory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
and use that factory to StartNew any task involved in GUI control updating.
You need to launch the async operation from an UI thread (main thread):
await Task.Run(DoYourStuffAsync);
This is equivalent to:
await Task.Run(DoYourStuffAsync).ConfigureAwait(true);
If the boolean argument of ConfigureAwait (bool continueOnCapturedContext) is true, the code that is below the await (also called continuation) will be executed in the calling thread (UI thread).
What I suggest is to do all your processing in an async way, create an outcome object, and then update the UI element in the continuation with the outcome object.
In this way you are using the UI thread only for UI stuff.
In this code:
public async Task v_task()
{
await Task.Run(() => Console.WriteLine("Hello!"));
}
public async void v1()
{
await v_task();
// some other actions...
}
public void ButtonClick()
{
v1();
Console.WriteLine("Hi!");
}
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
I mean, what should be my concerns about race conditions working with async/await? All async methods are mandatory executed in the same caller's thread? Should I use mutex on possible shared state? If yes, how could I detect what are the shared state objects?
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
Only the Console.WriteLine within the Task.Run.
I mean, what should be my concerns about race conditions working with async/await?
I suggest you start by reading my async intro, which explains how await actually works.
In summary, async methods are usually written in a serially asynchronous fashion. Take this code for example:
CodeBeforeAwait();
await SomeOtherMethodAsync();
CodeAfterAwait();
You can always say that CodeBeforeAwait will execute to completion first, then SomeOtherMethodAsync will be called. Then our method will (asynchronously) wait for SomeOtherMethodAsync to complete, and only after that will CodeAfterAwait be called.
So it's serially asynchronous. It executes in a serial fashion, just like you'd expect it to, but also with an asynchronous point in that flow (the await).
Now, you can't say that CodeBeforeAwait and CodeAfterAwait will execute within the same thread, at least not without more context. await by default will resume in the current SynchronizationContext (or the current TaskScheduler if there is no SyncCtx). So, if the sample method above was executed in the UI thread, then you would know that CodeBeforeAwait and CodeAfterAwait will both execute on the UI thread. However, if it was executed without a context (i.e., from a background thread or Console main thread), then CodeAfterAwait may run on a different thread.
Note that even if parts of a method run on a different thread, the runtime takes care of putting any barriers in place before continuing the method, so there's no need to barrier around variable access.
Also note that your original example uses Task.Run, which explicitly places work on the thread pool. That's quite different than async/await, and you will definitely have to treat that as multithreaded.
Should I use mutex on possible shared state?
Yes. For example, if your code uses Task.Run, then you'll need to treat that as a separate thread. (Note that with await, it's a lot easier to not share state at all with other threads - if you can keep your background tasks pure, they're much easier to work with).
If yes, how could I detect what are the shared state objects?
Same answer as with any other kind of multi-threaded code: code inspection.
If you call an async function, your thread will perform this function until it reaches an await.
If you weren't using async-await, the thread would yield processing until the awaited code was finished and continue with the statement after the await.
But as you are using async-await, you told the compiler that whenever the thread has to wait for something, you have some other things it can do instead of waiting, The thread will do those other things until you say: now await until your original thing is finished.
Because of the call to an async function we are certain that somewhere inside there should be an await. Note that if you call an async function that doesn't await you get a compiler warning that the function will run synchronously.
Example:
private async void OnButton1_clickec(object sender, ...)
{
string dataToSave = ...;
var saveTask = this.MyOpenFile.SaveAsync(dataToSave);
// the thread will go into the SaveAsync function and will
// do all things until it sees an await.
// because of the async SaveAsync we know there is somewhere an await
// As you didn't say await this.MyOpenfile.SaveAsync
// the thread will not wait but continue with the following
// statements:
DoSomethingElse()
await saveTask;
// here we see the await. The thread was doing something else,
// finished it, and now we say: await. That means it waits until its
// internal await is finished and continues with the statements after
// this internal await.
Note that even if the await somewhere inside SaveAsync was finished, the thread will not perform the next statement until you await SaveTask. This has the effect that DoSomethingElse will not be interrupted if the await inside the SaveAsync was finished.
Therefore normally it's not useful to create an async function that does not return either a Task or a Task < TResult >
The only exception to this is an event handler. The GUI doesn't have to wait until your event handler is finished.
I create a new BackgroundWorker every time I need to do any Async task and after the work is done I Dispose it but I've a doubt if that completely disposes it because the Dispose method is implemented by System.ComponentModel.Component
In a typical run of the program, thousands of them may be created. Is it okay if millions of them (to be on the safe side) get created or should I do it some other way?
Most of the async work is I/O and I can't use async/await because I'm using .NET 4 (can't use 4.5).
I've wrapped the whole thing in this method:
public void AsyncDo(Action Action, Action ActionFinish = null)
{
using (BackgroundWorker bw = new BackgroundWorker()) {
bw.DoWork += () => Action();
bw.RunWorkerCompleted += (s, e) =>
{
if (ActionFinish != null)
ActionFinish();
if (e.Error != null)
OnException(e.Error);
};
bw.RunWorkerAsync();
}
}
Based on the answers, I've updated it with
Task t = new Task(action);
t.Start();
But I get a cross-thread error when I do actionFinish() by combining it with action or calling t.ContinueWith(). This wasn't the case in the BGW, it didn't require invoking for RunWorkerCompleted. I can't change every call to this method to make them use invoking, what should I do?
BackgroundWorker is specifically designed to allow code to run in the background with respect to the UI thread, while also allowing simple synchronization with the UI.
If you need to do any async task, just use Task - that's what it's designed for. If you don't have .NET 4+, you'll need to use Thread (or better, ThreadPool.QueueUserWorkItem) instead - but that's even more complex (while looking deceptively simple). As always, http://www.albahari.com/threading/ should be your starting point when trying to implement multi-threading (or asynchronous code in general) :)
EDIT:
To get a behaviour close to what you had originally with BackgroundWorker, you can simply add a continuation to run on the UI thread:
var task = Task.Factory.StartNew(yourAction);
task.ContinueWith(yourResultAction, TaskScheduler.FromCurrentSynchronizationContext());
All of this is strongly typed, so it's quite easy to pass an arbitrary value from the yourAction task (running on a worker thread) to the yourResultAction task (running on the UI thread). Note that the TaskScheduler.FromCurrentSynchronizationContext() must be run on the UI thread, of course.
You can wrap this in a simple helper function that will just take the two actions, and return a task (either the original task, or the continuation task - that depends on what you want to do with it).
Also, Microsoft.Bcl.Async brings most of .NET 4.5+'s await goodness to .NET 4.0 - after all, await is all in the compiler, it doesn't need a new runtime to work. Working with await is much simpler than working with continuations, especially when doing error handling.
A race condition occurs when two or more threads access shared data, for writing, at the
same time. (How to deal with race conditions is covered later in this chapter in the “Synchronizing
Resources” section.) If you try to update the UI from another thread, .NET Framework throws an
InvalidOperationException containing the following message: "Cross-thread operation not
valid: Control 'ctrlName' accessed from a thread other than the thread it was
created on."
To solve the problem, change the worker_RunWorkerCompleted method
as follows:
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (this.InvokeRequired) {
this.Invoke(
new Action(ActionFinish));
}
else {
ActionFinish();
}
}
In the worker_RunWorkerCompleted method, you now check the InvokeRequired
property. This property is defined in the Control class, and as such is present on all the controls on a page. InvokeRequired is set to false if you call it from the UI thread and true
otherwise.
The Invoke method takes as the first parameter a delegate, meaning any method can be
placed there. The new Action() constructor call is used to make sure that you
get a delegate. If your method has a different signature, you must change that constructor
accordingly. The rest of the parameters of the Invoke method are sent directly to the method
you want to run. Invoke places the method call in a queue to be picked up by the UI thread.
A better solution ?
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e { this.Dispatcher.Invoke(()=> //statement); }
It is enough to call the Dispatcher.Invoke method in all the situations. This call
ensures that the lambda expression ()=> //statement is run by the UI thread,
regardless from which thread the method is called.
A BackgroundWorker and a task are both windows processes so I don't know why you need both. A class is also a process, but I like using a separate class rather than a task.
Imports System.ComponentModel
Module Module1
Sub Main()
Dim backgroundWorker As New MyBackGroundWorker
backgroundWorker.Dispose()
End Sub
End Module
Class MyBackGroundWorker : Implements IDisposable
Dim backgroundWorker As New BackgroundWorker
Sub Dispose() Implements IDisposable.Dispose
Me.Dispose()
End Sub
End Class
So let's say I have a method such as ThreadPool.QueueTask(Delegate d).
Some of these delegates need to return values, but as they cannot do this (being passed as delegates) they will need to take a value by reference as a parameter. Once the task is completed this value will have been altered, so the calling method needs to know this.
Essentially, the method passing the task to the threadpool should be waiting until it has completed.
What is the best way to do this? Should I just do Threadpool.QueueTask(Delegate d, EventWaitHandle e), or is there a more elegant way which would be obvious to people unfamiliar with that kind of thing?
Kind regards,
Fugu
You can use a ManualResetEvent:
public void TaskStartMethod()
{
ManualResetEvent waitHandle = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(o=>
{
// Perform the task here
// Signal when done
waitHandle.Signal();
});
// Wait until the task is complete
waitHandle.WaitOne();
}
Essentially, the method passing the
task to the threadpool should be
waiting until it has completed.
The above code does that, but now I have a question: if your method is waiting for the task to be completed, then why do you even bother to perform the task on a separate thread? In other words, what you're describing is sequential execution of code rather than parallel, so the use of the ThradPool is pointless.
Alternately, you might might want to use a separate delegate as a callback:
public delegate void OnTaskCompleteDelegate(Result someResult);
public void TaskStartMethod()
{
OnTaskCompleteDelegate callback = new OnTaskCompleteDelegate(OnTaskComplete);
ThradPool.QueueUserWorkItem(o=>
{
// Perform the task
// Use the callback to notify that the
// task is complete. You can send a result
// or whatever you find necessary.
callback(new Result(...));
});
}
public void OnTaskComplete(Result someResult)
{
// Process the result
}
Update (1/24/2011):
You might not even need the callback delegate, you can just directly call OnTaskComplete and that should do the job too:
public void TaskStartMethod()
{
ThradPool.QueueUserWorkItem(o=>
{
// Perform the task
// Call the method when the task is complete
OnTaskComplete(new Result(...));
});
}
Depends on how you are doing it. To me it sounds a little like you have thread A putting a single task on the thread pool, then waiting for that to finish. That does not sound very helpful. If you are putting one task on the thread pool and waiting, just do it in your own thread.
But that is probably not what your doing!
I can see two possible good ways for using the thread pool. Thread A has multiple things that it wants to kick off in parallel, and then wait for them all to finish. In this case you need to store a handle to all of the tasks (or a result class), so you can wait for them all to finish. You can make use of semiphores or various synchronization tools (I don't do c# specifically) to avoid having to busy poll.
Another way is to use a callback at the end of the task. Thread A kicks off the task on the thread pool, then exists. The task has a handle back to the class that kicked it off, and calls a callback type function when it is completed to do finalisation type stuff.
I have written a class that checks a POP3 account and I'd like it to execute on a thread other than the UI thread.
To do this, I've chosen the asynchronous route.
In order to get the result from pop3delegate.BeginInvoke(null,null) I need to call EndInvoke but doing this in the UI thread blocks rendering the UI unusable.
I could use the IAsyncResult object and check the IsComplete property, but this involves putting in a loop which checks and this in turn locks up the UI.
What I'm looking for is a way to get a percentage complete or some sort of a status from the POP3 class, which in turn updates the UI and also allows the UI to be usable to do other tasks. I'll also need to call the EndInvoke method at some point in order to catch any exceptions thrown on the worker thread.
Any suggestions?
Try using BackgroundWorker class, its was designed to do exactly what you need.
Example and more details on msdn: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Try the Backgroundworker class.
Use a BackgroundWorker. It also saves you the trouble of marshalling data back and forth between UI and background trheads, and it allows progress notifications and cancelling.
Use event and threadpool
var asyncResult = pop3delegate.BeginInvoke(null,null);
ThreadPool.RegisterWaitForSingleObject(
asyncResult.WaitHandle, FunctionToCallWhenDone, null, TimeSpan.Infinite, true);
This will call your FunctionToCallWhenDone when data arrives. You're also using ThreadPool which should be cheaper than creating own thread. However, as Kurt Schelfthout noted you'll have to do something like uielement.Invoke(()=>{some code}) to change UI.
You don't need to block or loop, you can simply pass a callback method (delegate) as the first parameter of your BeginInvoke call, here you can call EndInvoke process exceptions etc.
private delegate int LongRunningTaskHandler();
static void Main(string[] args) {
LongRunningTaskHandler handler = LongRunningTask;
handler.BeginInvoke(MyCallBack, null);
Console.ReadLine();
}
private static void MyCallBack(IAsyncResult ar) {
var result = (LongRunningTaskHandler)((AsyncResult) ar).AsyncDelegate;
Console.WriteLine(result.EndInvoke(ar));
}
public static int LongRunningTask()
{
Thread.Sleep(5000);
return 42;
}