I have this scenario where I try to handle an event on the same thread as it was created. Which is commonly done in the UiThread, but I'm not on the UiThread to start with. I have some test with basically the following steps. I have left out some details. I am not really sure whether or not this should act as I think it should .
First I check the Id of the current thread
var myThreadId = Thread.CurrentThread.ManagedThreadId;
I create a SynchronizationContext and set is as current
var _context = new SynchronizationContext();
SynchronizationContext.SetSynchronizationContext(_context);
Then I send some action to the context (We are now on another thread)
_context.Send(x => _action(sender, e), null);
Inside this action, I check the ThreadId again
Assert.Equal(myThreadId, Thread.CurrentThread.ManagedThreadId);
This fails. Am I not supposed to be on my original thread again?
If you create a new SynchronizationContext, it will always wrap the Thread Pool and never execute Send or Post on the UI thread.
From MSDN;
The SynchronizationContext class is a base class that provides a
free-threaded context with no synchronization.
For example;
void Button_Click(object sender, EventArgs e)
{
var context = SynchronizationContext.Current;
// this is executred on the UI thread.
context.Send(() =>
{
// this is also executed on the UI thread.
});
Task.Run(() =>
{
// this is executed on a worker thread
context.Send(() =>
{
// this is still executed on the UI thread!
});
}
// what you are doing will always execute on a worker thread.
var myNewContext = new SynchronizationContext();
SynchronizationContext.SetSynchronizationContext(myNewContext);
myNewContext.Send(() =>
{
// this will run on a worker thread.
}
}
Further Reading
Parallel Computing - It's All About the SynchronizationContext
Creating a new SynchronizationContext and using Send or Post is exactly the same as a synchronous delegate invocation as if you'd do it yourself. The code is rather simple (taken from the source):
public virtual void Send(SendOrPostCallback d, Object state)
{
d(state);
}
You're trying to mimic the operation of custom contexts, such as the DispatcherSynchronizationContext for example, which is aware of the WPF's UI message loop thread. That behavior does not happen here.
If you're coming from the UI thread, you'll need to capture the context and pass it along.
You can see this more clearly inside the DispatcherSynchronizationContext which queues work to the UI using the Dispatcher class:
/// <summary>
/// Synchronously invoke the callback in the SynchronizationContext.
/// </summary>
public override void Send(SendOrPostCallback d, Object state)
{
// Call the Invoke overload that preserves the behavior of passing
// exceptions to Dispatcher.UnhandledException.
if(BaseCompatibilityPreferences.GetInlineDispatcherSynchronizationContextSend() &&
_dispatcher.CheckAccess())
{
// Same-thread, use send priority to avoid any reentrancy.
_dispatcher.Invoke(DispatcherPriority.Send, d, state);
}
else
{
// Cross-thread, use the cached priority.
_dispatcher.Invoke(_priority, d, state);
}
}
Related
I am trying to have a system.timer calculate a object and return it to the calling tread in C#. If I calculate it the main trad then i get the object, but if I try to calculate the same in a system.timer I do not get any value back.
How to return a object from a system.timer an use it in the main tread?
public MainWindow()
{
Timer execute = new Timer();
execute.Interval = 5000;
execute.Elapsed += UpdatePending;
execute.Start();
InitializeComponent();
}
private void UpdatePending(Object source, System.Timers.ElapsedEventArgs e)
{
DataTable pending = new Repository().GetPending();
if (pending?.Rows.Count > 0)
{
dataGrid_Pending.DataContext = pending;
}
}
The dataGrid_Pending is not updating when I do this, but it is if I run the code in the main tread:
DataTable pending = new Repository().GetPending();
if (pending?.Rows.Count > 0)
{
dataGrid_Pending.DataContext = pending;
}
I made this Helper Class to run things to the UI Thread for my WPF Application
public static class InvokeUI
{
/// <summary>
/// Execute an Action in the Appropriate UI Thread
/// <para>Will Invoke the UI if you are not already in the Appropriate UI Thread</para>
/// <para>Runs Synchronously</para>
/// </summary>
/// <param name="action"></param>
public static void CheckAccess(Action action)
{
try
{
Dispatcher dispatcher = Application.Current.Dispatcher;
if (dispatcher.CheckAccess())
{
action();
return;
}
dispatcher.Invoke(delegate
{
try
{
action();
}
catch (Exception ex)
{
// Log This Error
}
}, DispatcherPriority.Render);
}
catch
{
// The Dispatcher might throw here during closing and after the UI has already been disposed
}
}
}
You use it like this
InvokeUI.CheckAccess(() =>
{
dataGrid_Pending.DataContext = pending;
// Your UI Update
});
This is option number 4 from the answer JonasH provided.
How to return a object from a system.timer an use it in the main tread?
You need to politely ask the UI thread to run some code on your behalf. There are many ways to do this
SynchronizationContext.Post
Control.Invoke
TaskScheduler.FromCurrentSynchronizationContext
Dispatcher.Invoke
Some of these require you to save an object to use in your timer event. If you are using WPF the dispatcher is probably easiest to use, since you can use the static Application.Current.Dispatcher to get it:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => DataContext = pending));
Note that whenever you are dealing with multiple threads, and timers.timer will by default invoke the event handler on a thread pool thread, you cannot access the UI, and you have to ensure the code is thread safe.
You might consider using a DispatcherTimer instead, since this will invoke events on the UI thread, removing the problem. This is the best approach if your event handler is fairly fast, say ~50ms or so.
If it is slower it might be more useful to run the event on a background thread, but then you need to worry about what will happen if one event handler does not finish before the next tick occur, in addition to any thread safety concerns.
I have a method that is "partially" async, meaning that one code path runs async and the other runs synchronously. I can't currently make the synchronous part async, although I may be able to in the future.
public async Task UpdateSomethingAsync(){
if (ConditionIsMet){
await DoSomethingAsync;
}else{
DoSomethingSynchronous;
}
}
Both DoSomethingAsync and DoSomethingSynchronous are I/O bound. Calling this method from the Winforms UI thread with "await" causes it to block the UI thread if the Synchronous path is taken, which is to be expected.
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This blocks if the DoSomethingSynchronous path is taken, causing UI to
//become unresponsive.
await UpdateSomethingAsync();
}
So off to Stephen Cleary's blog I go. His suggestion (although for CPU bound code instead of I/O bound) is to run the method with Task.Run, as if it were completely synchronous, while documenting that the method is "partially" async. However, events raised by DoSomethingSynchronous now cause an exception, I believe due to the fact that they are now on a different thread from the UI.
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This no longer blocks, but events will not marshal back to UI Thread
//causing an exception.
await Task.Run(()=> UpdateSomethingAsync());
}
How can this be fixed?
Don't update the UI, or any model bound to the UI inside of UpdateSomethingAsync or any of the methods that it calls. Create a class that will hold the data required to update your UI, and return an instance of that class from UpdateSomethingAsync.
DoSomethingAsync will return a Task<ThatClassYouCreated> and DoSomethingSynchronous just returns an instance of ThatClassYouCreated. Then, back in MyDropDownBox_DropDownClosed after you await UpdateSomethingAsync, use the instance returned by UpdateSomethingAsync to update your UI or your model.
public class UpdatedInformation
{
public int UpdateId { get; set; }
public string UpdatedName { get; set; }
public DateTimeOffset Stamp { get; set; }
// etc, etc...
}
public class YourForm : Form
{
private async Task<UpdatedInformation> DoSomethingAsync()
{
var result = new UpdatedInformation();
// Something is awaited...
// Populate the properties of result.
// Do not modify your UI controls. Do not modify the model bound to those controls.
return result;
}
private UpdatedInformation DoSomethingSynchronous()
{
var result UpdatedInformation();
// Populate the properties of result.
// Do not modify your UI controls. Do not modify the model bound to those controls.
return result;
}
private async Task<UpdatedInformation> UpdateSomethingAsync()
{
if (ConditionIsMet)
{
return await DoSomethingAsync();
}
else
{
return await Task.Run(DoSomethingSynchronous);
}
}
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
var updatedInformation = await UpdateSomethingAsync();
// Now use updatedInformation to update your UI controls, or the model bound to
// your UI controls.
model.Id = updatedInformation.UpdateId;
// etc...
}
}
In your event handler, you can use Invoke() to update the UI like this:
private void someEventHandler() // <- it might have params
{
// ... possibly some other code that does NOT update the UI ...
this.Invoke((MethodInvoker)delegate {
// ... it's safe to update the UI from in here ...
});
// ... possibly some other code that does NOT update the UI ...
}
I don't know who keeps doing it, but my comments below this post keep getting deleted.
This answers the TITLE of the question, which was:
How do I marshal an event from Task.Run back to the UI thread?
When you receive an event from a different thread, this is a perfectly valid way of updating the UI.
Sicne you state that "[..] DoSomethingSynchronous [is] I/O bound" you could also make it async by wrapping the IO bound operation within DoSomethingSynchronous in a Task.Run.
So if DoSomethingSynchronous is something like
public void DoSomethingSynchronous(...)
{
// some UI work
// blocking sysnchornous IO operation
var res = IoOperation();
// some more UI work
}
you could rewrite it to.
public async Task DoSomethingSynchronous(...)
{
// some UI work
// no-UI-Thread blocking IO operation
var res = await Task.Run(() => IoOperation()).ConfigureAwait(true);
// some more UI work
}
the .ConfigureAwait(true) could maybe omited but ensures that the code after the await will be scheduled in the orignal sync-context i.e. the UI-Thread.
You then obviously need to rename the method and such, but this will make the code more maintainable if you someday can use a true asycn IO in DoSomethingSynchronous
Since UpdateSomethingAsync needs to access the UI context, it shouldn't be wrapped in a Task.Run call. (You should very rarely, need to call an async method from Task.Run, usually only if the method is implemented incorrectly and you can't fix it.)
Instead DoSomethingSynchronous should be the thing you call from Task.Run. After all, the purpose of that method is to asynchronously run a synchronous method in a thread pool thread. So only use it for the synchronous method you want run in a thread pool thread, not the (supposedly) asynchronous method that needs to access the UI context.
WinUI 3 respects the below method.
DispatcherQueue.TryEnqueue(() =>
{
//Code to Update the UI
});
Figured I'd answer this myself after some more research. Most of the other answers are correct in some way, but don't necessarily explain the whole deal in one go, so I'll try to sum up here.
This first snippet from the question works event wise, but blocks if the Synchronous path in UpdateSomethingAsync is taken. Events work because "await" automatically captures the SynchronizationContext (this is key) for the UI thread, such that any events raised from UpdateSomethingAsync are marshalled back to the UI, via the SynchronizationContext. This is just the normal way of using async/await:
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This blocks if the DoSomethingSynchronous path is taken, causing UI to
//become unresponsive, but events propagate back to the UI correctly.
await UpdateSomethingAsync();
}
Task.Run works in much the same way, if you aren't using it to run an async method. In other words, this works without blocking and will still send events to the UI thread, because UpdateSomethingAsync is replaced with a Synchronous method. This is just the normal usage of Task.Run:
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//UpdateSomethingAsync is replaced with a Synchronous version, and run with
// Task.Run.
await Task.Run(UpdateSomethingSynchronously());
}
However, the original code in question is Async, so the above doesn't apply. The question poses the following snippet as a possible solution, but it errors out with an Illegal Cross Thread call to the UI when an event is raised, because we are using Task.Run to call an Async method, and for some reason this does not set the SynchronizationContext:
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This no longer blocks, but events raised from UpdateSomethingAsync
//will cause an Illegal Cross Thread Exception to the UI, because the
//SyncrhonizationContext is not correct. Without the SynchronizationContext,
//events are not marshalled back to the UI thread.
await Task.Run(()=> UpdateSomethingAsync());
}
What does seem to work is to use Task.Factory.StartNew to assign the UI SynchronizationContext to the Task using TaskScheduler.FromCurrentSynchronizationContext, like so:
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This doesn't block and will return events to the UI thread sucessfully,
//because we are explicitly telling it the correct SynchronizationContext to use.
await Task.Factory.StartNew(()=> UpdateSomethingAsync(),
System.Threading.CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext);
}
What also works, and is very simple but "lies" a little to the caller, is to simply wrap DoSomethingSynchronous in Task.Run:
public async Task UpdateSomethingAsync(){
if (ConditionIsMet){
await DoSomethingAsync;
}else{
await Task.Run(DoSomethingSynchronous);
}
}
I consider this a little bit of a lie, because the method is not really fully Async in the sense that it spins off a Thread Pool thread, but may never pose an issue to a caller.
Hopefully this makes sense. If any of this is proven incorrect please let me know, but this is what my testing has uncovered.
I want to know if its possible to get UI Thread context when using Asyn/await method. If yes, how?
Code written using WPF/MVVM pattern:
long asyncTimeChecker = 0;
int prevSec2 = 0;
/// <summary>
/// Button Click Command
/// </summary>
private void ExeTimerActivate(object o)
{
if (!IsTimerStart)
{
ActivateAsyncTicToc();
TimerState = "Stop";
}
else if (IsTimerStart)
{
ActivateAsyncTicToc();
TimerState = "Start";
}
IsTimerStart = !IsTimerStart;
}
/// <summary>
/// Call Method By Async/Await
/// </summary>
private async void ActivateAsyncTicToc()
{
IsTimerStartAsync = !IsTimerStartAsync;
var task1 = Task.Run(() => AsyncTicToc());
await task1;
}
/// <summary>
/// I tried to UI access by other thread what use Async/Await
/// </summary>
private void AsyncTicToc()
{
while (IsTimerStartAsync)
{
System.Threading.Thread.Sleep(10);
AsyncTimeText = $"{asyncTimeChecker / 1000}.{asyncTimeChecker % 1000}";
asyncTimeChecker += 10;
/// ========================================
/// This Position Get CrossThread Problem
/// ========================================
if (prevSec2 < asyncTimeChecker / 1000)
{
prevSec2++;
if (TimerColor2.Color == Colors.Blue)
TimerColor2.Color = Colors.Red;
else
TimerColor2.Color = Colors.Blue;
}
}
}
I know we can get the UI thread using Dispatcher, but want to know if its possible using async/await.
You are wrapping your async call in a task. This defeats the whole statemachine, and ends up using a threadpool thread needlessly.
The call and any continuations ends up in another thread and therefore can't access the UI without marshalling.
At minimum you should be doing this if you absolutely need to use an async void - it's just awaiting the task, and not wrapping it.
private async void ActivateAsyncTicToc()
{
try
{
IsTimerStartAsync = !IsTimerStartAsync;
await AsyncTicToc();
}
catch (Exception e)
{
// make sure you observe exceptions in async void
}
}
Even better, let the async propagate using async Task:
private async Task ActivateAsyncTicToc()
{
IsTimerStartAsync = !IsTimerStartAsync;
await AsyncTicToc();
}
Which looks suspect anyway, you should probably be doing this (eliding async and await) and just passing the task through to someone else who will await. This is a small performance gain:
private Task ActivateAsyncTicToc()
{
IsTimerStartAsync = !IsTimerStartAsync;
return AsyncTicToc();
}
In fact this is a mine-field and I'd be here all day.
You need to start reading about async and await:
Stephen Cleary Async and Await
Stephen Cleary Eliding Async and Await
Stephen Cleary Don't Block on Async Code
Asynchronous programming with async and await (C#)
Using Async And Await To Update The Ui Thread
First of all, you could use await Task.Delay(10) instead of Thread.Sleep(10) and change your AsyncTicToc method to async Task without starting a thread. This will make changing the control in the UI thread (the context from which you awaited).
Second, to update the UI from other threads, if you don't want to use the dispatcher directly, you can use the abstraction over it: the SynchronizationContext class. See more info here.
Example: SynchronizationContext.Current.Post(action, actionParameter);
Third, It's more appropriate to use a view model and binding. If you use WPF that it synchronizes the threads for property changes for you.
While it is possible to "reach out" from another thread to the UI thread using Dispatcher or SynchronizationContext, I strongly recommend not doing this. This is because it makes your logic less testable and more tied to its environment. In the case of Dispatcher, it is strongly tied to running in a WPF environment; SynchronizationContext is better, but it is still tied to running in some kind of environment.
With this kind of an approach, you have a dependency from your logic to a UI thread like this:
UI code => background thread logic => UI thread
Instead, use IProgress<T> and Progress<T> from your background thread logic to communicate progress reports back to its caller, which decides how to display those progress reports. Then your dependency looks like this:
UI code => background thread logic
and your background thread logic doesn't rely on a UI thread being present. This makes it more resuable and more testable.
From UI (thread1) I want to create a progress UI(thread2).
Progress UI creates a task in thread3 and waits for its completion.
The task(thread3) completes and invoke closing of progress UI which must be executed in thread2.
For closing operation I use AsyncOperationManager to capture context of thread2 and then execute POST method from thread4.
But closing always happens from some another thread.
All the code below is from ProgressWindows class.
_currentTask = new Progress<double>(Close); // I call this in progress UI constructor.
// This is invoked in constructor of Progress class which is used inside ProgressWindow.
_asyncOperation = AsyncOperationManager.CreateOperation(null);
public static void Run2(Action action)
{
Debug.WriteLine(":: Run2 in thread: {0}", Thread.CurrentThread.ManagedThreadId);
var th = new Thread(_ =>
{
Debug.WriteLine(":: StartNew in thread: {0}", Thread.CurrentThread.ManagedThreadId);
var progress = new ProgressWindow();
progress.Run(action);
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
public void Run(Action action)
{
Debug.WriteLine(":: Run in thread: {0}", Thread.CurrentThread.ManagedThreadId);
SetupProgressBar();
RunTask(action);
ShowDialog();
}
private void RunTask(Action action)
{
Task.Factory.StartNew(action).ContinueWith(_ => _currentTask.OnCompleted(null));
}
private void Close(object state)
{
Debug.WriteLine(":: Close in thread: {0}", Thread.CurrentThread.ManagedThreadId);
Hide();
Close();
}
The question is:
private void RunTask(Action action)
{
Task.Factory.StartNew(action).ContinueWith(_ => _currentTask.OnCompleted(null));
}
You see, _currentTask.OnCompleted(null) is invoked from another thread, but _currentTaskof type Progress uses context captured in the UI thread, but OnCompletedis always invoked from another thread other than UI thread. Why? It must be in the same context.
Update 1:
Mixing System.Threading.SynchronizationContext with System.Windows.Form.WindowsFormsSynchronizationContext and System.Windows.Threading.DispatcherSynchronizationContext
Synchronization context in asynchronous WCF per call service
Force WCF to use one thread
AsyncOperationManager works differently depending on context where AsyncOperationManager.CreateOperation was invoked.
Denending on context, AsyncOperationManager.CreateOperation may create three contexts:
System.Threading.SynchronizationContext
System.Windows.Form.WindowsFormsSynchronizationContext System.Windows.Threading.DispatcherSynchronizationContext
In my case when I capture context before ShowDialog, I capture thread sync context,
but if I invoke AsyncOperationManager.CreateOperation within OnLoad event, I capture
System.Windows.Form.WindowsFormsSynchronizationContext or DispatcherSynchronizationContext
depending on WindowsForms or WPF is used. That was the source of error.
I would cut it down to just using Dispatcher.BeginInvoke.
But to leave all the code with Progress, I just placed AsyncOperationManager.CreateOperation and creating new background thread inside OnLoad of ProgressWindow UI. It has resolved the issue.
[Windows forms application & .NET 4.0]
I need to execute database access methods that return objects (either list of classes or simple classes).
Also i need to open forms that are responsive while main thread does initialization.
I need to run these on separate threads keeping the User Interface responsive and of course to be able to pass the results back to main thread for UI updates.
I have been reading books regarding the various ways for this.
I understand that my job can be done by:
BackGroundWorker
Thread Class
Task Class
Which one i should dive into ?
Update: using the suggested Task class i am getting errot for cross thread safety using this:
private void BtnCheckClick(object sender, EventArgs e)
{
var itm = Task<JDEItemLotAvailability>.Factory.StartNew(() =>
Dal.GetLotAvailabilityF41021(
txtLot.Text,
cmbMcu.SelectedItem.ToString(),
cmbLocn.SelectedItem.ToString())
);
lblDescriptionValue.Text = itm.Result.Description;
lblItemCodeValue.Text = itm.Result.Code;
lblQuantityValue.Text = itm.Result.AvailableQuantity.ToString();
LotFocus(true);
}
On the above exmaple i am getting the exception in cmbMcu control not the txtLot.
I would use the Task class, it's really easy to synchronize it and it already provides a support for returning objects.
var task = Task.Factory.StartNew(
() => GetDatabaseData(someArguments),
TaskCreationOptions.LongRunning);
// Example method
public DataSet GetDatabaseData(object args) { ... }
this this tells a scheduler to create and begin a new task and gives it a hint that it might be a good idea not to use a thread-pool thread, if the scheduler uses a thread-pool. Anyway you can now decide how do you want to synchronize.
For example to achieve similar behaviour as in Gregor Primar's answer, you can set up a continuation using ContinueWith method as follows,
task.ContinueWith(oldTask => ProcessReturnedData(oldTask.Result));
// Example method
public IEnumerable<SomeEntity> ProcessReturnedData(DataSet data) { ... }
which will schedule calling the ProcessReturnedData method after the task object has done executing. Note that this will be called even if task fails for some reason, so it may not be always a good solution - or you would have to do some checks in the provided delegate.
If you want to do a non-blocking wait on the main thread and use the returned object there, you can simply use the Wait method.
task.Wait(); // Makes current thread wait until the task is comnpleted.
DataSet result = task.Result; // Accessing the result object.
I hade done a lot of projects using Thread, however Task should be more easy to use.
Here is demo how make async operations using Threads.
This is the class that will return data to ui:
public class MyAsyncClass
{
public delegate void NotifyComplete(DataSet data);
public event NotifyComplete NotifyCompleteEvent;
//Starts async thread...
public void Start()
{
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(DoSomeJob));
t.Start();
}
void DoSomeJob()
{
//just wait 5 sec for nothing special...
System.Threading.Thread.Sleep(5000);
if (NotifyCompleteEvent != null)
{
//TODO: fill your data...
DataSet ds = new System.Data.DataSet();
NotifyCompleteEvent(ds);
}
}
}
And here is ui implementation:
MyAsyncClass myClass = null;
private void button2_Click(object sender, EventArgs e)
{
myClass = new MyAsyncClass();
myClass.NotifyCompleteEvent += new MyAsyncClass.NotifyComplete(myClass_NotifyCompleteEvent);
//here I start the job inside working class...
myClass.Start();
}
//here my class is notified from working class when job is completed...
delegate void myClassDelegate(DataSet data);
void myClass_NotifyCompleteEvent(DataSet data)
{
if (this.InvokeRequired)
{
Delegate d = new myClassDelegate(myClass_NotifyCompleteEvent);
this.Invoke(d, new object[] { data });
}
else
{
//TODO: show your data
MessageBox.Show("Data retrieved!");
}
}