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());
Related
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
I was messing up with c#'s await/async when I wrote the following program:
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Test();
while (true) { }
}
static async void Test()
{
var t = Task.Run(()=> Thread.Sleep(1000));
await t;
throw new Exception("This exception happens in a worker thread");
}
}
When I run this program, I can clearly see in Visual Studio's thread window that the exception happens in a Worker Thread, rather than the Main Thread, this leads me to believe that when I await a task, my method can be finished by another thread.
However, when I open a new windows forms application and add the following event handler:
async void button1_Click(object sender, EventArgs e)
{
var task = Task.Run(() => Thread.Sleep(1000));
await task;
button1.Text = "I'm in the main thread!"; //this works
}
This works, so I notice that in a console application my Test function is resumed by a worker thread, while in a Windows Forms application, it's always resumed by the main thread.
Why is this? Is it reliable?
Yes. It is reliable.
When you do await, the current SynchronizationContext is captured so that when it continues after the await, this context will be used to execute the code.
In GUI applications, the current SynchronizationContext is a context that will execute code on the UI thread.
In Console Applications, the current SynchronizationContext is null, therefore the Task continues on a thread-pool thread.
Take a look at this blog post.
As I explain in my async intro, by default await will capture a "context" and resume execution of its async method in that context.
Technically, this context is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current.
In everyday terms, this means that the context is a UI context if the method is running on a UI thread; it is an ASP.NET request context if the method is servicing an ASP.NET request; and it is most likely the thread pool context in all other situations.
Note that this is default behavior. You can specify that the method does not need to resume on its context by awaiting the result of ConfigureAwait(continueOnCapturedContext: false). In this case, it is likely that the rest of the method will be executed on a thread pool thread; but technically this just means that the method will be executed "somewhere" and you don't care where.
Yes, this is correct and one of the intended uses of async / await.
The Task that you are awaiting is what happens asynchronously. When it resumes, it resumes on the calling thread, which will be the UI thread in the case of a WinForms event handler.
Note that it is possible for you to change this behavior using Task.ConfigureAwait(False). When the task is configured this way, it will not pass control back to the original thread and will instead resume on the task's thread.
All of this behavior is dependant on the application's current SynchonizationContext though. Some application types will have different contexts which can subtly change the behaviors. Console Applications are a good example of this, as they do not set a synchronization context by default, and will resume on the Task's thread. You can change this if you want by creating a context for the console app, as shown here.
I'm working on a user control for UWP and it updates some of its visuals upon certain calls. However, since the core .NET library has been shifted around and the threading classes have been severely cut back, I don't know how to identify from the method in the user control if the calling thread is the UI thread or not so it knows whether or not to use the dispatcher to change a dependency property.
Anyone know how to do this?
EDIT: The dispatcher functionally can be "invoked" async fine on the UI thread - however, I really don't know if this is a good idea - to try to invoke on the main thread from the main thread via the dispatcher. If anyone has a reason this is fine or bad, that would also contribute to answering the question. If there's no reason to not use the dispatcher on the main thread, then I guess there's no problem.
I have found the solution...
CoreDispatcher.HasThreadAccess returns a bool indicating if you are on the UI thread or not.
My son just encountered this as an Issue so I thought I would add an updated answer.
The Main UI thread can be accessed using the Core Dispatcher CoreWindow.GetForCurrentThread().Dispatcher or Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher
Below is a class that implements the Core Dispatcher and tests whether the calling thread is the Main UI Thread. If so it invokes the action, otherwise calls Dispatcher.RunAsync to execute it on the Main UI thread.
class Threading {
private static CoreDispatcher Dispatcher =>
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
public static async void ThreadSafe(DispatchedHandler action)
{
// Calls Dispatcher.RunAsync to run a method on the Main UI Thread
IAsyncAction UiThread(DispatchedHandler proc) => Dispatcher.RunAsync(CoreDispatcherPriority.Normal, proc);
// Checks to see if this was called from the Main UI thread
// If we are in the Main UI thread then Invoke the action
// Otherwise: Send it to run in the Main Ui Thread.
if (Dispatcher.HasThreadAccess) { action.Invoke(); } else { await UiThread(action); };
}
}
The above class could be used like so:
// Some event handler callback
private void SomeCallback(object sender)(){
void line() => Frame.Navigate(typeof(PageName));
Threading.ThreadSafe(line);
}
// Pass a handle to the control and a string to update it's text property
internal static void ChangeControlText(dynamic ctrl , string v)
{
void line() {ctrl.Text= v;}
ThreadSafe(line);
}
At many blogs, tutorials and MSDN I can read that accessing UI elements from non-UI threads is impossible - ok, I'll get an unauthorized exception. To test it I've written a very simple example:
// simple text to which TextBlock.Text is bound
private string sample = "Starting text";
public string Sample
{
get { return sample; }
set { sample = value; RaiseProperty("Sample"); }
}
private async void firstButton_Click(object sender, RoutedEventArgs e)
{
await Job(); // asynchronous heavy job
commands.Add("Element"); // back on UI thread so this should be ok?
}
private async Task Job()
{
// I'm not on UI Thread ?
await Task.Delay(2000); // some other job
Sample = "Changed"; // not ok as not UI thread?
commands.Add("Element from async"); // also not ok?
}
I've a Task which is being run asynchronously. In that Task I want to change my property (which will raise PropertyChanged) and add element to ObservableCollection. As it is run async, I shouldn't be able to do that, but I get no exception and the code is working fine. Thus my doubts and misunderstanding:
why don't I get an exception?
is it ok to raise PropertyChanged in async Task?
is it ok to modify ObservableCollection in async Task, or should I return Task<ICollection> and after obtaining the result modify the ObservableCollection- Clear it and Fill it?
when am I in Task on UI thread and when not?
in the code above in firstButton_Click is it ok to manage UI elements after awaiting the Task? Am I always back on UI thread?
To test it more I've put my property change and collection modification in other thread:
System.Threading.Timer newThreadTimer = new System.Threading.Timer((x) =>
{
Sample = "Changed"; // not UI thread - exception
commands.Add("Element from async"); // not UI thread - exception
}, null, 1000, Timeout.Infinite);
In above code my thinking is ok - just after the first or second line I get an exception. But what with the first code? Is it only a luck that my Taskwas run on UI thread?
I suspect that this is very basic thing and my misunderstanding, but I need some clarification and thus this question.
When awaiting on a Task, the SynchronizationContext of the current thread is captured (specifically in the case of Task by the TaskAwaiter). The continutation is then marshaled back to that SynchronizationContext to execute the rest of the method (the part after the await keyword).
Lets look at your code example:
private async Task Job()
{
// I'm not on UI Thread ?
await Task.Delay(2000); // some other job
Sample = "Changed"; // not ok as not UI thread?
commands.Add("Element from async"); // also not ok?
}
When you await Task.Delay(2000), the compiler implicitly captures the SynchronizationContext, which is currently your WindowsFormsSynchronizationContext. When the await returns, the continuation is executed in the same context, since you didn't explicitly tell it not to, which is your UI thread.
If you changed your code to await Task.Delay(200).ConfigureAwait(false), the continuation would not be marshalled back to your current SynchronizationContext, and would run a ThreadPool thread, causing your UI element update to throw an exception.
In your timer example, the Elapsed event is raised via a ThreadPool thread, hence why you get an exception that you are trying to update an element which is controlled by a different thread.
Now, let's go over your questions one by one:
why don't I get exception?
As said, the await Task.Delay(2000) executed the Continuation on the UI thread, which made it possible to update your controls.
is it ok to Raise properties in async Task?
I am not sure what you mean by "Raise properties", but if you mean raise a INotifyPropertyChanged event, then yes, it is ok to execute them not in a UI thread context.
is it ok to modify ObservableCollecition in async Task, or should I
return Task and after obtaining the result modify Observable - Clear
it and Fill it?
If you have an async method and you want to update a UI bound element, make sure you marshal the continuation on the UI thread. If the method is called from the UI thread and you await its result, then the continuation will implicitly be ran on your UI thread. In case you want to offload work to a background thread via Task.Run and make sure your continuation is ran on the UI, you can capture your SynchronizationContext using TaskScheduler.FromCurrentSynchronizationContext() and explicitly pass it the continuation
when am I in Task on UI thread and when not?
A Task is a promise of work that will be done in the future. when you await on a TaskAwaitable from the UI thread context, then you are still running on the UI thread. You are not in the UI thread if:
Your async method is currently executing from a thread different then the UI thread (either a ThreadPool thread or a new Thread)
You offload work to a background ThreadPool thread using Task.Run.
in the code above in firstButton_Click is it ok to manage UI elements
after awaiting the Task? Am I always back on UI thread?
You will be back to the UI thread as long as you don't explicitly tell your code not to return to its current context using ConfigureAwait(false)
The PropertyChanged event is automatically dispatched to the UI thread by WPF so you can modify properties that raise it from any thread. Before .NET 4.5 this was not the case for ObservableCollection.CollectionChanged event and thus, adding or removing elements from a thread other than the UI one, would cause an exception.
Starting in .NET 4.5 CollectionChanged is also automatically dispatched to the UI thread so you don't need to worry about that. This being said, you'll still need to access UI elements (such as a button for instance) from the UI thread.
OK first of all, it's nothing that I need to implement or anything. I just need to know the answer because someone more experienced told me that asynchronous execution doesn't necessarily have to involve a new thread as threads are somewhat heavy constructs, which confused me a lot and I couldn't agree.
Now let's say, I have two methods - Execute() and ExecuteAsync(). Execute() is running on the main thread. I want to call ExecuteAsync() from within Execute() and I don't care whenever it completes executing, but when it does, may be (or may be not) I want use it's return value. That's a typical example of an asynchronous execution, right?
I know I can do this using BackgroundWorker or IAsyncResult (Delegate.BeginInvoke()), but AFAIK under the hood they spawns a secondary CLR Thread/ThreadPool Thread.
So is it anyhow possible to execute the method ExecuteAsync() asynchronously without the help of a second thread?
EDIT : I think this edit will clarify the scenario further. Invoking ExecuteAsync() is NOT the only (or last) task for Execute() to perform. Execute() should continue it's own tasks without caring about the execution of ExecuteAsync() method.
Here is an example of a program that uses asynchrony and never ever uses more than one thread:
public class Foo
{
private int _value;
private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
public int Value
{
get
{
return _value;
}
set
{
_value = value;
var oldTCS = tcs;
tcs = new TaskCompletionSource<bool>();
oldTCS.SetResult(true);
}
}
public Task ValueChanged()
{
return tcs.Task;
}
}
private static void Main(string[] args)
{
Foo foo = new Foo();
foo.ValueChanged()
.ContinueWith(t =>
{
Console.WriteLine(foo.Value);
}, TaskContinuationOptions.ExecuteSynchronously);
foo.Value = 5;
}
The Task returned from ValueChanged will be completed the next time that Value is changed. The user of the Foo class can get that returned task and wire up continuations to run on that task based on an operation that has not yet happened. Then, at some point in the future, the value of foo is changed, and the continuation will run. Note that the foo object could be passed to some other function, entirely unknown to Main, that ends up setting the value (to show why you might want to do something like this).
No new thread is needed to create the Task, nor to execute the continuation.
Here's another example that's much more practical:
We'll start with this simple (extension) method that takes a form and returns a Task indicating when that form is next closed:
public static class FormExtensions
{
public static Task WhenClosed(this Form form)
{
var tcs = new TaskCompletionSource<bool>();
form.FormClosed += (sender, args) => tcs.SetResult(true);
return tcs.Task;
}
}
Now we can have this in one of our forms:
private async void button1_Click(object sender, EventArgs args)
{
Form2 otherForm = new Form2();
otherForm.Show();
await otherForm.WhenClosed();
//take some data from that form and display it on this form:
textBox1.Text = otherForm.Name;
}
Creating and showing another form never involves the creation of new threads. Both this form and the new form use entirely the one UI thread to be created and modified.
The creation of the Task returned from WhenClosed does not need to create a new thread at all.
When the Task is awaited, no new thread is created. The current method ends and the UI thread is left to go back to processing messages. At some point, that same UI thread will do something that results in the second form being closed. That will result in the continuation of the task running, thus returning us to our button click handler where we set the text of the textbox.
All of this is done entirely with the UI thread, no other threads have been created. And yet we've just "waited" (without actually waiting) for a long running operation to finish (the user to put some information into the second form and then close it) without blocking the UI thread, thus keeping the main form responsive.
So is it anyhow possible to execute the method ExecuteAsync() asynchronously without the help of a second thread?
It is possible for some methods to run asynchronously without using a new thread. This can be done via Asynchronous I/O with a signal, for example. Most of the framework's new Async methods added in .NET 4.5 async IO whenever possible instead of threads.
This is why it's a good idea to not assume asynchronous == new thread. While asynchrony can be implemented using threading, it is not always implemented this way. It's better to just think of an asynchronous operation as an operation that (hopefully) will not block, and will complete at some point in the future.
Coroutines are a common way to implement several logical threads using a single physical thread. Older operating systems used this and other related concepts to implement cooperative multitasking.
In this context you may also be interested in continuation-passing style and Eric Lippert has a good blog series on this very topic - Part 1, Part 2, Part 3, Part 4, Part 5.