How can I wait for a (TPL) Task to start? - c#

After starting a new task with
Task waitUntilSaved = Task.Factory.StartNew(() => { ... });
how can I wait until it is started? I.e. I want to continue only in the flow when I know the task has started and waitUntilSave.Status equals TaskStatus.Running.
Or is this kind of meaningless, because the task might have started without actually executing the first statement?
EDIT:
Yes, I do want to make sure that the first statement is called. Here's my scenario. I have a Web UI which I test drive through Selenium. There's one element (widget) that is shown while the UI is doing a save operation. In the test I want to make sure that
A) The widget appears while saving.
B) Continue with the test once the widget is invisible again (and thus saving has completed).
For this I wrote:
Task waitUntilSaved = Task.Factory.StartNew(() =>
{
Driver.FindElementOrNull(By.Id("isSavingPosition"), FindBehavior.WaitUntilDisplayed);
Driver.FindElement(By.Id("isSavingPosition"), FindBehavior.WaitUntilHidden);
});
Thread.Sleep(10); // how can I get rid of this?
Assert.AreEqual(TaskStatus.Running, waitUntilSaved.Status);
saveButton.Click();
waitUntilSaved.Wait();
The first statement of the task will stop the task and wait until the widget is displayed. The second statement of the task simply waits until the widget disappears again.
The first statement after starting the task - the very ugly one I want to get rid of - is making sure (or rather increasing the chance) that the first statement of the task gets executed before clicking the save button.
If saveButton.Click gets executed too early, the task might fail to catch the appearance and disappearance of the "is saving"-widget and thus halt the task forever.

This is meaningless because the thread the task runs on can be paused by the OS at any time. It can be paused directly after you have determined that it is started.
Probably, your synchronization scheme needs rethinking.

You could try to do something like this:
ManualResetEvent mre = new ManualResetEvent(false);
Task waitUntilSaved = Task.Factory.StartNew(() => {
mre.Set();
});
mre.WaitOne();
// code after...

Related

c# async await confuses me, seems to do nothing

EDIT: Updating LongTask() to be await Task.Delay(2000); makes it work how I need, so thanks for the answers, y'all!
I am trying to call an async function from within a sync function to let the sync function keep going before the async function is finished. I don't know why the code below waits for LongTask() to complete before continuing. I thought it should only do that if I did await LongTask(). Can someone help me understand what I'm missing?
C# fiddle here
using System;
using System.Diagnostics;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
var timer = new Stopwatch();
timer.Start();
LongTask();
timer.Stop();
long ms = timer.ElapsedMilliseconds;
Console.WriteLine(ms.ToString());
}
async static void LongTask()
{
Task.Delay(2000).Wait();
}
}
Here's the short short intro to async/await
You know when you're playing some God type game where you e.g. set your settlers building a load of buildings, or cutting trees/making food etc and then you have literally nothing else to do except sit and watch them finish, then you can start again, getting the buildings to churn out knights or catapults or whatever?
It's a bit of a waste of life, you sitting there doing nothing other than waiting for something to finish, then you can carry on with some other task..
As a human you probably don't do that; you go make a cup of coffee, call a friend, hit the punchbag, maybe even go play the space exploration game, set the autopilot of whatever ship to guide you to some star system on a journey that'll take 5 mintues of waiting and watching stars pass.. Autopilot set, coffee made, buildings still not finished, bored of the punchbag.. So you go clean up..
This isn't doing things in parallel; you aren't wiping the floor with a cloth while stirring the coffe and chatting on the phone, but it's making great use of your time, cracking through the todo list by pouring a load of energy into one thing, getting as far as you can, then switching to the next thing. You do one thing at once, but when you get stuck you move onto another thing. If you sat and waited for everything you'd need 10 copies of you to get 10 stop/start jobs done
async/await is the same thing. It takes syncronous code - something that is done from start to finish in one long operation that is the sole focus of your thread's attention, even if there's a 5 minute Wait() in the middle of it where it literally sits and does nothing for 5 minutes - and chops it up into a bunch of separate methods that are controlled by a process that allows the thread to pick up where it left off of
Marking a method async is the indicator to C# that the compiler is allowed to invisbly cut the method up into pieces that can be put down and picked up when needed
await is the indicator where you're saying "I've reached a point where I need some operation to finish before I can progress any further with this; go and find something else to do". When it encounters an await your thread will stop work on your code because it's being told it to do nothing more until the background operation completes (it's not important what is doing the work, lets imagine it's some background thread) and your thread will go and do something else until the result is ready. This really simplifies a lot of programming related stuff because you only ever deal with one thread - it's code that behaves like syncronous code but goes and does something else instead of doing nothing when it gets stuck
As a keyword await has to be followed by something that is awaitable, usually a Task or Task<T> - it represents the operation that is already set to happen. When the operation is finished and the thread returns await also helpfully unwraps the Task object that was controlling this process, and gives you the result..
If you take nothing else away from this, at the very least learn:
you must mark a method as async if you want to use await inside it. You should generally make the return type of an sync method as either Task (if it returns no value) or Task<X> (if it returns a value of type X). You should also call the method a name ending in ..Async
When you start some operation that works asyncronously (you call some method that is called ..Async), and you get a Task<X> object in return, use await on it to get the X you actually want
Making an async method means the method that calls it also has to be async, and the method that calls that also has to be async.. and.. All the way up the tree and out of your code. That's how your thread can "escape" when it has to go find something else to do - it needs to escape out of your code, so you make a route for that to happen by declaring "async all the way up"
I said in the comments not to use a console app. Let's imagine you have a Windows Forms app. Win Forms apps typically have one thread that does everything. One thread draws the UI, and when you click a button it comes and runs all the code you put in the button_Click() handler. While it's doing that it's not doing its normal job of drawing the UI. You can set statusLabel.Text = "Downloading data.." as the very first line of the method, and you can launch a download of a 1 gig file, and then you can set the status Label to "Finished " + downloadedFile.Length. You click the button, and you see nothing - the UI of your app jams frozen for 30 seconds while the file downloads. Then it suddenly says "Finished 1024000000" in the label:
void button_Click(object sender, EventArgs e){
statusLabel.Text = "Starting download";
string downloadedFile = new SomeHttpDownloadStringThing("http://..");
statusLabel.Text = "Finished " + downloadedFile.Length;
}
Why? Well.. the thread that draws the UI and would have painted the label pixels on the screen got really busy downloading the file. It went into that SomeHttpDownloadStringThing method and didn't come out for 30 seconds, then it came out, set the status label text again, then it left your code and went back to whatever land it normally lives in. It drew the pixels on screen "Finished..". It never even knew it had to draw "Starting download".. That data was overwritten well before it picked up its paintbrush again
Let's turn it async:
async void button_Click(object sender, EventArgs e){
statusLabel.Text = "Starting download";
string downloadedFile = await SomeHttpDownloadStringThingAsync("http://..");
statusLabel.Text = "Finished " + downloadedFile.Length;
}
SomeHttpDownloadStringThing returned a string. SomeHttpDownloadStringThingAsync returned a Task<string>. When the UI thread hits that await imagine it tells some background thread to go download the file, puts this method on pause, and returns out of it and goes back to drawing the UI. It paints the label as "Starting ..." so you see it, and then maybe finds some other stuff to do. If you had a Timer ticking up counting how long the download had been then your timer would increment nicely too - bcause the UI thread is free to do it, it's not sitting awaiting for Windows to do the download while it does nothing other than wait.
When the download finishes, the thread is called back to where it was and it picks up from there. It doesn't run the first code again, it doesn't set the status label to "Starting" again.
It literally starts from the SomeHttpDownloadStringThingAsync part as if it had never left, the await converts the Task<string> into a string of the downlaoded file, and then the UI thread can set the "Finished.." text
The whole thing is just like the syncronous version, except that little bit in the middle where the UI thread was allowed to go back to its regular job of drawing pixels on the screen and handling other user interaction
This is why I say console apps are hard work for understanding async/await because their UI doesn't obviously do anything else while an await is in progress, unless you've arranged for something to happen, but that's more work. UI apps automatically have other stuff going on, and if you jam up the threads that do that stuff, they freeze, and turn "Not responding"
If you have an eagle eye, you'll have spotted async void on the handler even though I said "if you have a void method, make it return Task when you make it async" - winforms event handlers are a bit of a special case in that regard, you cannot make them async Task but they're an exception rather than a rule. For now, rule of thumb - avoid async void
As already mentioned in the comments:
you have to use await Task.Delay(2000) to tell the compiler that you want run Task.Delay(2000) asynchronous.
If you take a closer look in the example provided by you the compiler shows a warning:
This async methods lacks 'await'operators and will run synchronously [...]
This will hopefully demonstrate it better:
static async Task Main(string[] args)
{
var timer = Stopwatch.StartNew();
var t1 = LongTask();
var t2 = LongTask();
Console.WriteLine("Started both tasks in {0}", timer.Elapsed);
await Task.WhenAll(t1, t2);
timer.Stop();
Console.WriteLine("Tasks finished in {0}", timer.Elapsed);
}
async static Task LongTask()
{
await Task.Delay(2000);
}
Notice the change in return types of functions. Notice the output, too. Both task are waiting for something (in this case delay to expire) in parallel and at the same time, the Main function is able to continue running, printing text and then waiting for the outcome of those functions.
It is important to understand that the execution of an async function runs synchronously until it hits the await operator. If you don't have any await in an async function it will not run asynchronously (and compiler should warn about it). This is applied recursively (if you have several nested awaits) until you hit something that is actually going to be waited for. See example:
static async Task Main(string[] args)
{
var timer = Stopwatch.StartNew();
var t1 = LongTask(1);
Console.WriteLine("t1 started in {0}", timer.Elapsed);
var t2 = LongTask(2);
Console.WriteLine("Started both tasks in {0}", timer.Elapsed);
await Task.WhenAll(t1, t2);
timer.Stop();
Console.WriteLine("Tasks finished in {0}", timer.Elapsed);
}
async static Task LongTask(int id)
{
Console.WriteLine("[{0}] Before subtask 1", id);
await LongSubTask1();
Console.WriteLine("[{0}] Before subtask 2", id);
await LongSubTask2();
Console.WriteLine("[{0}] After subtask 1", id);
}
async static Task LongSubTask1(int id)
{
Console.WriteLine("[{0}] LongSubTask1", id);
await Task.Delay(1000);
}
async static Task LongSubTask2(int id)
{
Console.WriteLine("[{0}] LongSubTask2", id);
await Task.Delay(1000);
}
If you run it, you will see that the execution runs synchronously all the way down to Task.Delay call and only then it returns all the way back to the Main function.
In order to benefit from async/await, you have to use it all the way down to where it ends up calling some I/O (network, disk, etc.) you will need to wait for (or some other event that does not require constant polling to figure out, or artificially created like delay in that sample). If you need to do some expensive computation (that does not have anything async in it) without occupying some particular thread (say, UI thread in GUI application), you'd need to explicitly start new task with it, which at some later point you can await for to get its result.

How to make sure a task is started and safely start it if not?

I get an IEnumerable<Task> tasks from somewhere that I do not control. I don't know if the tasks are manually created using new Task, Task.Run, or if they are a result of an async method call async Task DoSomethingAsync().
If I do await Task.WhenAll(tasks), I risk hanging indefinitely because maybe one or more of the tasks are not started.
I can't do tasks.ForEach(t => t.Start()), because then I will get an InvalidOperationException "Start may not be called on a promise-style task" if it's from an async method call (already started).
I can't do await Task.WhenAll(tasks.Select(t => Task.Run(async () => await t))) because each t still does not start just by awaiting it.
I assume the solution has something to do with checking each task's Status and Start() based on that, but I also assume that it can be tricky because that status could change at any time, right? If this is still the way to go, which statuses would be correct to check and what threading issues should I worry about?
Non working case example:
//making an IEnumerable as an example, remember I don't control this part
Task t = new Task( () => Console.WriteLine("started"));
IEnumerable<Task> tasks = new[] {t};
//here I receive the tasks
await Task.WhenAll(tasks);//waits forever because t is not started
Working case example:
//calls the async function, starting it.
Task t = DoSomethingAsync();
IEnumerable<Task> tasks = new[] {t};
//here I receive the tasks and it will complete because the task is already started
await Task.WhenAll(tasks);
async Task DoSomethingAsync() => Console.WriteLine("started");
If for whatever reason you cannot change the code to not return unstarted tasks, you can check Status and start task if it has Created status:
if (task.Status == TaskStatus.Created)
task.Start();
All other task statues indicate that task is either completed, running, or being scheduled, so you don't need to start tasks in that statuses.
Of course in theory this introduces race condition, because task can be started right between your check and Start call, but, as correctly pointed by Servy in comments - if there ever is race condition here - that means another party (which created that task) is also trying to start it. Even if you handle exception (InvalidOperationException) - another party is unlikely to do that, and so will get exception while trying to start their own task. So only one side (either you, or code that created that task) should be trying to start it.
That said - much better than doing this is to ensure you might never get unstarted task in the first place, because it's just bad design to return such tasks to external code, at least without explicitly indicating that (while it's for some use cases ok to use unstarted task internally).

Could a BeginInvokeOnMainThread method be looping and causing a memory leak?

I have an application that works but after a while when I debug on my iPhone it hangs the phone and the only way I can recover is a hard reset of the button on the side and the home button.
First of all, could that be because my application has a memory leak?
Here's the code for the application. In particular, I am looking at the BeginInvokeOnMainThread method. Can someone tell me if they can see if there could be any problems with the way that it is implemented? Also, what's the purpose of the .ContinueWith((arg).
namespace Japanese
{
public partial class PhrasesFrame : Frame
{
CancellationTokenSource cts = new CancellationTokenSource();
public PhrasesFrame(PhrasesPage phrasesPage)
{
InitializeComponent();
this.phrasesPage = phrasesPage;
AS.phrasesFrame = this;
Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token).ContinueWith((arg) => { }));
}
public void Disappearing()
{
cts.Cancel();
}
public async Task ShowCards(CancellationToken ct)
{
AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories();
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
}
}
ContinueWith
First, let's address your question about .ContinueWith((arg) => { })). ContinueWith tells more code to execute once the original Task has completed. In our case, the code inside of ContinueWith will run once Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token) has finished.
In this case, there is no code inside of ContinueWith, so we can remove it.
Freezing
Yes, I can see that this code has potential to freeze the UI.
BeginInvokeOnMainThread will queue an Action to run on the Main Thread (also known as the UI Thread). The Main Thread is constantly listening for user input (tapping a button on the screen, pinch-to-zoom, etc.), and if this thread is busy doing a long-running task, it will not be able to respond to a user's input until it has finished; thus your app will appear frozen.
The code await Task.Delay(500); is being called by the Main Thread. We are thus telling the Main Thread to freeze itself for 500 milliseconds, and looping that indefinitely.
One solution would be to wrap this code in Task.Run which would put it in a background-thread and free the Main Thread to listen/respond to user input.
Task.Run(async () =>
{
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
More Threading Recommendations
Only use BeginInvokeOnMainThread when you need to update the UI. 99% of code can run on a background thread with no problems. The 1%, however, is code that updates the UI; any code that updates the UI must be run on the Main Thread.
If a task that takes longer than the refresh rate of the screen to execute, perform it on a background thread. For example, if the screen's refresh rate is 60Hz, it is updating 60-times per second, every 16.7ms. So if we have a block of code that takes 20ms to execute, we need to execute it on a background thread to ensure that we don't freeze the app and drop any frames.
The code above looks like it is accessing a database, which I would highly recommend moving to a background thread like so
await Task.Run(() => AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories());
First, if you are concerned about a memory leak, you can check for low-memory warnings in the device logs (accessible through XCode), or override the ReceiveMemoryWarning method in your app delegate to log an error.
Secondly, there's nothing obviously wrong with the way you're calling BeginInvokeOnMainThread that would cause a leak. The ContinueWith is a no-op that doesn't affect the operation of the code - I'm guessing it's there to avoid a compiler warning that you're not awaiting the task.
Thirdly, if you suspect that this code is causing a leak, you should use logging and/or breakpoints to confirm that it's behaving as expected. Is the task correctly cancelled when you navigate away from the page? Do you see multiple instances of of the ShowCards task running? If this code turns out to be behaving correctly, then the source of the hang lies elsewhere in your app. For instance, it looks like you're making a database call twice a second - maybe it's not cleaning up resources properly.

Any way to wait for all tasks to be complete in ActionBlock?

First of all, let me describe the flow of the program I am writing.
There is a list of objects in the GUI and when the user clicks on one, the object data is read from the disk and is loaded. This could take around 3-4 seconds.
Let's say the user is impatient and clicks on another object while the first one is still loading. The program will load the second object and at the same time, will cancel the loading for the first object.
As the user could spam load operations before any of them could complete successfully, I have implemented an action block to queue up all the load operations.
So I have an action block like this:
this.loadObjectActionBlock = new ActionBlock<CaseObject>(
c => this.LoadCaseData(CaseObject),
new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 10,
});
Every time the user has clicked on a Case Object, I will call:
this.loadObjectActionBlock.Post(CaseObject);
And the CaseObject will be processed by a function I have defined like this:
private void LoadCaseData(CaseObject caseObject)
{
caseObject.LoadCaseData();
}
What I need to do right now is, I need to wait until ALL CaseObjects are loaded so that I could continue my code after that.
I have tried detecting when all cases are processed by calling
if (this.loadObjectActionBlock.InputCount == 0)
{
this.loadObjectActionBlock.Complete();
}
after caseObject.LoadCaseData(); but this leads to strange results when load actions happen way too fast and the action block is told not to accept any more inputs. If I understand correctly, the InputCount property only looks at the number of jobs left in the queue.
So what I'd like to do is I'd like to await the ActionBlock like:
await this.loadObjectActionBlock.Completion;
when everything in the queue has been fully processed.
I may not be using the ActionBlock as it is intended to, so if there are any alternatives on this, please kindly suggest anything that I could read up on.
TLDR: I'd like to process multiple tasks (started by user) concurrently and wait for all to be complete then followed by a single task.
Thanks in advance :)
The program will load the second object and at the same time, will cancel the loading for the first object.
A queue is not the appropriate solution for this behavior, especially since a TPL block can only be completed once.
If you want to implement this behavior, simply ensure the cancellation token is observed before continuing with the next operation:
private static void ProcessCase(CaseObject caseObject, CancellationToken token)
{
caseObject.LoadCaseData();
token.ThrowIfCancellationRequested();
... // Further processing goes here
}
Called from the UI thread as:
static CancellationTokenSource _cts;
private static async Task ProcessCaseAsync(CaseObject caseObject)
{
if (_cts != null)
_cts.Cancel();
_cts = new CancellationTokenSource();
await Task.Run(() => ProcessCase(caseObject, _cts.Token));
}

starts new thread inside Task.ContinueWith

i am building a WPF app where it needs job1 runs in the background; when job1 ends, it switches back to the UI thread using Task.ContinueWith and makes changes to the UI according to job1's result (in my case, starts another popup) and starts job2 in the background.
The problem is that, while job1 runs in a separate thread as it should, job2 runs in the UI thread (it blocks popup2). Maybe because job2 is started inside the ContinueWith block of task1? But why? It worked the first time, why not second time? How to fix this problem?
Thanks in advance!
enterPop(PopupTypes.popup1);
var task1 = new Task(() => job1()); //task runs in another thread
task1.ContinueWith(previousTask =>
{
//**back in UI thread**
//check result of job 1, start another popup in UI
exitPopup();
enterPop(PopupTypes.popup2);
//**SUPPOSEDLY** starts another background thread for task 2
var task2 = new Task(()=> job2());
task2.ContinueWith(previousTask =>{
//do task in UI thread...
},TaskScheduler.FromCurrentSynchronizationContext());
task2.Start();
}, TaskScheduler.FromCurrentSynchronizationContext());
task.Start();
It's not clear to me what the enterPop() and exitPopup() methods are supposed to do, as the code example is missing that detail. Maybe they are displaying some kind of window in the GUI? It's also not clear what code exists in the "check result of job 1" part, "do task in UI thread", etc.
Without these details, it's impossible to know what your code is actually doing.
In any case, Hans's advice is correct. It's not really clear from the incomplete code example why you get the behavior you're seeing (for that matter, it's not really entirely clear to me what behavior you're seeing). But it's likely that if you'd written the code in the more usual async/await pattern, it would work fine:
enterPop(PopupTypes.popup1);
await Task.Run(() => job1()); //task runs in another thread
//**back in UI thread**
//check result of job 1, start another popup in UI
exitPopup();
enterPop(PopupTypes.popup2);
// starts another background thread for task 2
await Task.Run(()=> job2());
exitPopup();
//do task in UI thread...
For bonus points, have the job1() and job2() methods return the result that you check (per the commend in your code), and use something like var result = await Task.Run(() => job1()); to retrieve the value (instead of whatever mechanism you're using now).
In some cases TaskScheduler may decide to execute Task in the current thread, e.g. read the following example from Jeffrey Richter's book CLR via c#:
When a thread calls the Wait method, the system checks if
the Task that the thread is waiting for has started executing. If it
has, then the thread calling Wait will block until the Task has
completed running. But if the Task has not started executing yet, then
the system may (depending on the TaskScheduler) execute the Task using
the thread that called Wait. If this happens, then the thread calling
Wait does not block; it executes the Task and returns immediately
I believe something similar happens in your logic. TaskScheduler just follows your task queue and decides to execute it syncronously. The easiest way out is to start task2 in default scheduler
task2.Start(TaskScheduler.Default);

Categories