I have a class (Class A) that is responsible for running an async job in the background that looks like this:
public async void DoJob()
{
while (true)
{
var thingToDo = this.getNextThing();
if (thingToDo != null)
{
try
{
await this.performAction(thingToDo);
}
catch (Exception ex)
{
// file logging of error.
// then wait a certain period.
await Task.Delay(someInterval);
}
}
else
{
// Gets the interval that should be awaited until there is a
// thingToDo available.
var waitInterval = this.getWaitUntilNextThingAvailable();
// if there such an interval then wait for it.
if (waitInterval != null)
{
await Task.Delay(waitInterval.Value);
}
// else (basically when there is nothing to be done by this job)
// use an AsyncManualResetEvent to wait until its set.
else
{
await this.waitHandle.WaitAsync();
}
}
}
}
I am basically interested in the last else block - the one where I use an AsyncManualResetEvent (provided by the AsyncEx library)
I use an event provided by another class (Class B) to set the waitHandle. This is how the subscription looks like (note that this method is in Class B)
private event Action ChangeOccurred;
public void Attach(Action action)
{
this.ChangeOccurred += action;
}
And now onto my question : I use ChangeOccurred?.Invoke() to set the waitHandle such that Class A can be notified that there is something to do and continue performing things in the background.
Is Invoke() the right way? I am not sure if I should be using BeginInvoke() and EndInvoke instead? The event contains no date and is simply used as a signal that the async job can do things already.
The code in Class B where the ChangeOccurred event is invoked is synchronous.
Do not use BeginInvoke/EndInvoke. Those methods just call Invoke on a thread pool thread.
Using myEvent?.Invoke() is an appropriate way of raising the event, which (synchronously) sets the AsyncManualResetEvent. The fact that there's an asynchronous listener on the AsyncManualResetEvent doesn't matter.
On a side note, the latest (v5 preview) version of AsyncEx includes PauseToken
/ PauseTokenSource types which are really just a simple wrapper around AsyncManualResetEvent, but might make the intent of the code a bit clearer.
Related
I am using the System.Threading.Timer class in one of my projects and I've noticed that the callback methods are called before the previous ones get to finish which is different than what I was expecting.
For example the following code
var delta = new TimeSpan(0,0,1);
var timer = new Timer(TestClass.MethodAsync, null, TimeSpan.Zero, delta);
static class TestClass
{
static int i = 0;
public static async void MethodAsync(object _)
{
i++;
Console.WriteLine("method " + i + "started");
await Task.Delay(10000);
Console.WriteLine("method " + i + "finished");
}
}
has this output
method 1started
method 2started
method 3started
method 4started
method 5started
method 6started
method 7started
method 8started
method 9started
method 10started
method 11started
method 11finished
method 12started
method 12finished
Which of course is not thread safe. What I was expecting is that a new call would be made to the callback method after the previous call has succeeded and additionally after the delta period is elapsed.
What I am looking for is where in the docs from Microsoft is this behavior documented and maybe if there is a built in way to make it wait for the callback calls to finish before starting new ones
The problem of overlapping event handlers is inherent with the classic multithreaded .NET timers (the System.Threading.Timer and the System.Timers.Timer). Attempting to solve this problem while remaining on the event-publisher-subscriber model is difficult, tricky, and error prone. The .NET 6 introduced a new timer, the PeriodicTimer, that attempts to solve this problem once and for all. Instead of handling an event, you start an asynchronous loop and await the PeriodicTimer.WaitForNextTickAsync method on each iteration. Example:
class TestClass : IDisposable
{
private int i = 0;
private PeriodicTimer _timer;
public async Task StartAsynchronousLoop()
{
if (_timer != null) throw new InvalidOperationException();
_timer = new(TimeSpan.FromSeconds(1));
while (await _timer.WaitForNextTickAsync())
{
i++;
Console.WriteLine($"Iteration {i} started");
await Task.Delay(10000); // Simulate an I/O-bound operation
Console.WriteLine($"Iteration {i} finished");
}
}
public void Dispose() => _timer?.Dispose();
}
This way there is no possibility for overlapping executions, provided that you will start only one asynchronous loop.
The await _timer.WaitForNextTickAsync() returns false when the timer is disposed. You can also stop the loop be passing a CancellationToken as argument. When the token is canceled, the WaitForNextTickAsync will complete with an OperationCanceledException.
In case the periodic action is not asynchronous, you can offload it to the ThreadPool, by wrapping it in Task.Run:
await Task.Run(() => Thread.Sleep(10000)); // Simulate a blocking operation
If you are targeting a .NET platform older than .NET 6, you can find alternatives to the PeriodicTimer here.
What I am looking for is where in the docs from Microsoft is this behavior documented...
System.Threading.Timer
If processing of the Elapsed event lasts longer than Interval, the event might be raised again on another ThreadPool thread. In this situation, the event handler should be reentrant.
System.Timers.Timer
The callback method executed by the timer should be reentrant, because it is called on ThreadPool threads.
For System.Windows.Forms.Timer this post asserts that the event does wait. The documentation doesn't seem very specific, but in the Microsoft Timer.Tick Event official example the code shows turning the timer off and on in the handler. So it seems that, regardless, steps are taken to prevent ticks and avoid reentrancy.
...and if there is a built in way to make it wait for the callback calls to finish before starting new ones.
According to the first Microsoft link (you might consider this a workaround, but it's straight from the horse's mouth):
One way to resolve this race condition is to set a flag that tells the event handler for the Elapsed event to ignore subsequent events.
The way I personally go about achieving this objective this is to call Wait(0) on the synchronization object of choice as a robust way to ignore reentrancy without having timer events piling up in a queue:
static SemaphoreSlim _sslim = new SemaphoreSlim(1, 1);
public static async void MethodAsync(object _)
{
if (_sslim.Wait(0))
{
try
{
i++;
Console.WriteLine($"method {i} started # {DateTime.Now}");
await Task.Delay(10000);
Console.WriteLine($"method {i} finished # {DateTime.Now}");
}
catch (Exception ex)
{
Debug.Assert(false, ex.Message);
}
finally
{
_sslim.Release();
}
}
}
In which case your MethodAsync generates this output:
I have some c# code (MVC WebAPI) which iterates over an array of IDs in parallel and makes an API call for each entry. In the first version, the whole code was a simple, synchronous for loop. Now we changed that to a combination of Task.WhenAll and a LINQ select:
private async Task RunHeavyLoad(IProgress<float> progress) {
List<MyObj> myElements = new List<MyObj>(someEntries);
float totalSteps = 1f / myElements.Count();
int currentStep = 0;
await Task.WhenAll(myElements.Select(async elem => {
var result = await SomeHeavyApiCall(elem);
DoSomethingWithThe(result);
progress.Report(totalSteps * System.Threading.Interlocked.Increment(ref currentStep) * .1f);
}
// Do some more stuff
}
This is a simplified version of the original method! The actual method EnforceImmediateImport is called by this SignalR hub method:
public class ImportStatusHub : Hub {
public async Task RunUnscheduledImportAsync(DateTime? fromDate, DateTime? toDate) {
Clients.Others.enableManualImport(false);
try {
Progress<float> progress = new Progress<float>((p) => Clients.All.updateProgress(p));
await MvcApplication.GlobalScheduler.EnforceImmediateImport(progress, fromDate, toDate);
} catch (Exception ex) {
Clients.All.importError(ex.Message);
}
Clients.Others.enableManualImport(true);
}
}
Now I wonder, if this is "thread safe" per se, or if I need to do something with the progress.Report calls to prevent anything from going wrong.
From the docs:
Remarks
Any handler provided to the constructor or event handlers
registered with the ProgressChanged event are invoked through a
SynchronizationContext instance captured when the instance is
constructed. If there is no current SynchronizationContext at the time
of construction, the callbacks will be invoked on the ThreadPool.
For more information and a code example, see the article Async in 4.5:
Enabling Progress and Cancellation in Async APIs in the .NET Framework
blog.
Like anything else using the SynchronizationContext, it's safe to post from multiple threads.
Custom implementations of IProgress<T> should have their behavior defined.
On your question, internally, Progress only does invoking. It is up to the code you wrote to handle the progress on the other side. I would say that the line progress.Report(totalSteps * System.Threading.Interlocked.Increment(ref currentStep) * .1f); can cause a potential progress reporting issue due to the multiplication which is not atomic.
This is what happens internally inside Progress when you call Report
protected virtual void OnReport(T value)
{
// If there's no handler, don't bother going through the sync context.
// Inside the callback, we'll need to check again, in case
// an event handler is removed between now and then.
Action<T> handler = m_handler;
EventHandler<T> changedEvent = ProgressChanged;
if (handler != null || changedEvent != null)
{
// Post the processing to the sync context.
// (If T is a value type, it will get boxed here.)
m_synchronizationContext.Post(m_invokeHandlers, value);
}
}
On the code though, a better way to run in parallel is to use PLinq. In your current code, if the list contains many items, it will spin up tasks for every single item at the same time and wait for all of them to complete. However, in PLinq, the number of concurrent executions will be determined for you to optimize performance.
myElements.AsParallel().ForAll(async elem =>
{
var result = await SomeHeavyApiCall(elem);
DoSomethingWithThe(result);
progress.Report(totalSteps * System.Threading.Interlocked.Increment(ref currentStep) * .1f);
}
Please keep in mind that AsParallel().ForAll() will immediately return when using async func. So you might want to capture all the tasks and wait for them before you proceed.
One last thing, if your list is being edited while it is being processed, i recommend using ConcurrentQueue or ConcurrentDictionary or ConcurrentBag.
This is for an iOS app written in Xamarin. All my application code runs in the main thread (i.e. the UI thread).
The UI code does something as follows:
public async void ButtonClicked()
{
StartSpinner();
var data = await UpdateData();
StopSpinner();
UpdateScreen(data);
}
The UpdateData function does something as follows:
public Task<Data> UpdateData()
{
var data = await FetchFromServer();
TriggerCacheUpdate();
return data;
}
TriggerCacheUpdate ends up calling the following function defined below
public Task RefreshCache()
{
var data = await FetchMoreDataFromServer();
UpdateInternalDataStructures();
}
My question is how should TriggerCacheUpdate be written? The requirements are:
Can't be async, I don't want UpdateData and consequently
ButtonClicked to wait for RefreshCache to complete before
continuing.
UpdateInternalDataStructures needs to execute on the main (UI) thread, i.e. the thread that all the other code shown above executes on.
Here are a few alternatives I came up with:
public void TriggerCacheUpdate()
{
RefreshCache();
}
The above works but generates a compiler warning. Moreover exception handling from RefreshCache doesn't work.
public void TriggerCacheUpdate()
{
Task.Run(async() =>
{
await RefreshCache();
});
}
The above violates requirement 2 as UpdateInternalDataStructures is not executed on the same thread as everything else.
A possible alternative that I believe works is:
private event EventHandler Done;
public void TriggerCacheUpdate()
{
this.task = RefreshCache();
Done += async(sender, e) => await this.task;
}
Task RefreshCache() {
var data = await FetchMoreDataFromServer();
UpdateInternalDataStructures();
if (Done != null) {
Done(this, EventArgs.Empty);
}
}
Does the above work? I haven't ran into any problems thus far with my limited testing. Is there a better way to write TriggerCacheUpdate?
It's hard to say without being able to test it but it looks like your trigger cache update method is fine, it's your RefreshCache that needs to change. Inside of RefreshCache you are not waiting in the UI thread for the result of "data" to return so set the ConfigureAwait to false.
public async Task RefreshCache()
{
var data = await FetchMoreDataFromServer().ConfigureAwait(false);
UpdateInternalDataStructures();
}
Your event handler is async. That means, that even if you await for a Task to complete, that your UI remains responsive. So even if you would await for the TriggerCacheUpdate to return, your UI would remain responsive.
However, if you are really certain that you are not interested in the result of TriggerCachUpdate, then you could start a Task without waiting for it:
public Task<Data> UpdateData()
{
var data = await FetchFromServer();
Task.Run( () => TriggerCacheUpdate());
return data;
}
Note: careful: you don't know when TriggerCachUpdate is finished, not even if it ended successfully or threw an exception. Also: check what happens if you start a new TriggerCacheUpdate task while the previous one is not finished yet.
For those who want to use Task.Factory.StartNew, see the discussion about it in MSDN:
Task.Run vs Task.Factory.StartNew
I'm writing a networked application.
Messages are sent over the transport as such:
Network.SendMessage (new FirstMessage() );
I can register an event handler to be called when this message type arrives, like so:
Network.RegisterMessageHandler<FirstMessage> (OnFirstMessageReceived);
And the event gets fired:
public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs> e)
{
}
I'm writing a custom authentication procedure for my networked application, which requires around five messages to complete.
Without using the Task Parallel Library, I would be forced to code the next step of each procedure in the preceding event handler, like so:
public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs> e)
{
Network.SendMessage( new SecondMessage() );
}
public void OnSecondMessageReceived(EventArgs<SecondMessageEventArgs> e)
{
Network.SendMessage( new ThirdMessage() );
}
public void OnThirdMessageReceived(EventArgs<ThirdMessageEventArgs> e)
{
Network.SendMessage( new FourthMessage() );
}
public void OnFourthMessageReceived(EventArgs<FourthMessageEventArgs> e)
{
// Authentication is complete
}
I don't like the idea of jumping around the source code to code a portion of this and a portion of that. It's hard to understand and edit.
I hear the Task Parallel Library substantially simplifies this solution.
However, many of the examples I read using the Task Parallel Library were related to starting a chain of active tasks. What I mean by 'active', is that each task could start when called explicitly, like so:
public void Drink() {}
public void Eat() {}
public void Sleep() {}
Task.Factory.StartNew( () => Drink() )
.ContinueWith( () => Eat() )
.ContinueWith( () => Sleep() );
This is opposite from my event-based async pattern, in which each event handler method is called only when the message is received.
In other words, I can't do something like this (but I want to):
Task.Factory.StartNew( () => OnFirstMessageReceived() )
.ContinueWith( () => OnSecondMessageReceived() )
.ContinueWith( () => OnThirdMessageReceived() )
.ContinueWith( () => OnFourthMessageReceived() );
I've read this article, but I don't quite understand it. It seems like what I need has to do with TaskCompletionSource. If I wanted to make a task from my event-based async pattern like the code block above, what would it look like?
You're right about TaskCompletionSource, it's the key to transforming EAP (event-based asynchronous pattern) to TPL's Task.
This is documented here: https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/tpl-and-traditional-async-programming#exposing-complex-eap-operations-as-tasks
Here is the simplified code:
public static class Extensions
{
public static Task<XDocument> GetRssDownloadTask(
this WebClient client, Uri rssFeedUri)
{
// task completion source is an object, which has some state.
// it gives out the task, which completes, when state turns "completed"
// or else it could be canceled or throw an exception
var tcs = new TaskCompletionSource<XDocument>();
// now we subscribe to completed event. depending on event result
// we set TaskCompletionSource state completed, canceled, or error
client.DownloadStringCompleted += (sender, e) =>
{
if(e.Cancelled)
{
tcs.SetCanceled();
}
else if(null != e.Error)
{
tcs.SetException(e.Error);
}
else
{
tcs.SetResult(XDocument.Parse(e.Result));
}
};
// now we start asyncronous operation
client.DownloadStringAsync(rssFeedUri);
// and return the underlying task immediately
return tcs.Task;
}
}
Now, all you need to do, to make a chain of those operations, is just to set your continuations (which is not very comfortable at the moment, and the C# 5 await and async will help alot with it)
So, this code could be used like this:
public static void Main()
{
var client = new WebClient();
client.GetRssDownloadTask(
new Uri("http://blogs.msdn.com/b/ericlippert/rss.aspx"))
.ContinueWith( t => {
ShowXmlInMyUI(t.Result); // show first result somewhere
// start a new task here if you want a chain sequence
});
// or start it here if you want to get some rss feeds simultaneously
// if we had await now, we would add
// async keyword to Main method defenition and then
XDocument feedEric = await client.GetRssDownloadTask(
new Uri("http://blogs.msdn.com/b/ericlippert/rss.aspx"));
XDocument feedJon = await client.GetRssDownloadTask(
new Uri("http://feeds.feedburner.com/JonSkeetCodingBlog?format=xml"));
// it's chaining - one task starts executing after
// another, but it is still asynchronous
}
Jeremy Likness has a blog entry title Coroutines for Asynchronous Sequential Workflows using Reactive Extensions (Rx) that might interest you. Here is the question he tries to answer:
The concept is straightforward: there are often times we want an asynchronous set of operations to perform sequentially. Perhaps you must load a list from a service, then load the selected item, then trigger an animation. This can be done either by chaining the completed events or nesting lambda expressions, but is there a cleaner way?
When awaiting Dispatcher.RunAsync the continuation occurs when the work is scheduled, not when the work has completed. How can I await the work completing?
Edit
My original question assumed the premature continuation was caused by the design of the API, so here's the real question.
When awaiting Dispatcher.RunAsync using an asynchronous delegate, using await within the delegate's code, the continuation occurs when the await is encountered, not when the work has completed. How can I await the work completing?
Edit 2
One reason you may need to dispatch work that's already on the UI thread is to workaround subtle timing and layout issues. It's quite common for values of sizes and positions of elements in the visual tree to be in flux and scheduling work for a later iteration of the UI can help.
I found the following suggestion on a Microsoft github repository: How to await a UI task sent from a background thread.
Setup
Define this extension method for the CoreDispatcher:
using System;
using System.Threading.Tasks;
using Windows.UI.Core;
public static class DispatcherTaskExtensions
{
public static async Task<T> RunTaskAsync<T>(this CoreDispatcher dispatcher,
Func<Task<T>> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal)
{
var taskCompletionSource = new TaskCompletionSource<T>();
await dispatcher.RunAsync(priority, async () =>
{
try
{
taskCompletionSource.SetResult(await func());
}
catch (Exception ex)
{
taskCompletionSource.SetException(ex);
}
});
return await taskCompletionSource.Task;
}
// There is no TaskCompletionSource<void> so we use a bool that we throw away.
public static async Task RunTaskAsync(this CoreDispatcher dispatcher,
Func<Task> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) =>
await RunTaskAsync(dispatcher, async () => { await func(); return false; }, priority);
}
Once you do that, all you need to do is use the new RunTaskAsync method to have your background task await on the UI work.
Usage example
Let's pretend that this is the method that needs to run in the UI thread. Pay attention to the debug statements, which will help follow the flow:
public static async Task<string> ShowMessageAsync()
{
// Set up a MessageDialog
var popup = new Windows.UI.Popups.MessageDialog("Question", "Please pick a button to continue");
popup.Commands.Add(new Windows.UI.Popups.UICommand("Button 1"));
popup.Commands.Add(new Windows.UI.Popups.UICommand("Button 2"));
popup.CancelCommandIndex = 0;
// About to show the dialog
Debug.WriteLine("Waiting for user choice...");
var command = await popup.ShowAsync();
// Dialog has been dismissed by the user
Debug.WriteLine("User has made a choice. Returning result.");
return command.Label;
}
To await that from your background thread, this is how you would use RunTaskAsync:
// Background thread calls this method
public async void Object_Callback()
{
Debug.WriteLine("Object_Callback() has been called.");
// Do the UI work, and await for it to complete before continuing execution
var buttonLabel = await Dispatcher.RunTaskAsync(ShowMessageAsync);
Debug.WriteLine($"Object_Callback() is running again. User clicked {buttonLabel}.");
}
The output then looks like this:
Object_Callback() has been called.
Waiting for user choice...
User has made a choice. Returning result.
Object_Callback() is running again. User clicked Button 1.
Your question is assuming that you want to schedule (and wait for) work on a UI thread from a background thread.
You'll usually find your code is much cleaner and easier to understand (and it will definitely be more portable) if you have the UI be the "master" and the background threads be the "slaves".
So, instead of having a background thread await some operation for the UI thread to do (using the awkward and unportable Dispatcher.RunAsync), you'll have the UI thread await some operation for the background thread to do (using the portable, made-for-async Task.Run).
You can wrap the call to RunAsync in your own asynchronous method that can be awaited and control the completion of the task and thus the continuation of awaiting callers yourself.
Since async-await is centred on the Task type, you must orchestrate the work using this type. However, usually a Task schedules itself to run on a threadpool thread and so it cannot be used to schedule UI work.
However, the TaskCompletionSource type was invented to act as a kind of puppeteer to an unscheduled Task. In other words, a TaskCompletionSource can create a dummy Task that is not scheduled to do anything, but via methods on the TaskCompletionSource can appear to be running and completing like a normal job.
See this example.
public Task PlayDemoAsync()
{
var completionSource = new TaskCompletionSource<bool>();
this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
try
{
foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
{
// For each subsequent stroke plot, we need to start a new figure.
//
if (this.Sketch.DrawingPoints.Any())
this.Sketch.StartNewFigure(ppc.First().Position);
foreach (var point in ppc)
{
await Task.Delay(100);
this.Sketch.DrawingPoints.Add(point.Position);
}
}
completionSource.SetResult(true);
}
catch (Exception e)
{
completionSource.SetException(e);
}
});
return (Task)completionSource.Task;
}
Note: the main work being done on the UI thread is just some lines being drawn on screen every 100ms.
A TaskCompletionSource is created as the puppet master. Look near the end and you'll see that it has a Task property that is returned to the caller. Returning Task satisfies the compilers needs and makes the method awaitable and asynchronous.
However, the Task is just a puppet, a proxy for the actual work going on in the UI thread.
See how in that main UI delegate I use the TaskCompletionSource.SetResult method to force a result into the Task (since returned to the caller) and communicate that work has finished.
If there's an error, I use SetException to 'pull another string' and make it appear that an exception has bubbled-up in the puppet Task.
The async-await subsystem knows no different and so it works as you'd expect.
Edit
As prompted by svick, if the method was designed to be callable only from the UI thread, then this would suffice:
/// <summary>
/// Begins a demonstration drawing of the asterism.
/// </summary>
public async Task PlayDemoAsync()
{
if (this.Sketch != null)
{
foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
{
// For each subsequent stroke plot, we need to start a new figure.
//
if (this.Sketch.DrawingPoints.Any())
this.Sketch.StartNewFigure(ppc.First().Position);
foreach (var point in ppc)
{
await Task.Delay(100);
this.Sketch.DrawingPoints.Add(point.Position);
}
}
}
}
A nice way to work the clean way #StephenCleary suggests even if you have to start from a worker thread for some reason, is to use a simple helper object. With the object below you can write code like this:
await DispatchToUIThread.Awaiter;
// Now you're running on the UI thread, so this code is safe:
this.textBox.Text = text;
In your App.OnLaunched you have to initialize the object:
DispatchToUIThread.Initialize(rootFrame.Dispatcher);
The theory behind the code below you can find at await anything;
public class DispatchToUIThread : INotifyCompletion
{
private readonly CoreDispatcher dispatcher;
public static DispatchToUIThread Awaiter { get; private set; }
private DispatchToUIThread(CoreDispatcher dispatcher)
{
this.dispatcher = dispatcher;
}
[CLSCompliant(false)]
public static void Initialize(CoreDispatcher dispatcher)
{
if (dispatcher == null) throw new ArgumentNullException("dispatcher");
Awaiter = new DispatchToUIThread(dispatcher);
}
public DispatchToUIThread GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get { return this.dispatcher.HasThreadAccess; }
}
public async void OnCompleted(Action continuation)
{
if (continuation == null) throw new ArgumentNullException("continuation");
await this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => continuation());
}
public void GetResult() { }
}