Wait for Tasks to complete at shutdown without deadlocking - c#

At any given time, my WPF application has a bunch of async Tasks running on background threads/synchronization contexts. At shutdown, I need to set a CancellationToken and then wait for these tasks to complete gracefully before I can start tearing down native libraries they depend on. But some of the tasks have continuations that (need to) run on the main thread, so calling Task.WaitAll(_myTasks) from the same thread will deadlock. What I'd like to do is something like this:
while(!AreAllTasksComplete(_myTasks))
LetContinuationsThatAreWaitingForThisContextRun();
TearDownTheNativeLibraries();
But of course LetContinuationsThatAreWaitingForThisContextRun() does not exist. Is there any way to do what I'm trying to do? Do I need a completely different approach?

You can do
await Task.WhenAll(_myTasks);
TearDownTheNativeLibraries();

Related

async await task.run xamarin forms

I just would like to ensure I understood well the differences between async await and Task.run or Task.whenall
So async await is to process asynchronous methods. It means that there is an order of processing implied.
I run a long processing without blocking the main thread and I wait for the result to continue.
For Task.Run and Task.Whenall there is a new notion with multithreading. It means that I can launch a long process on a new thread and it doesn't wait to complete to continue the code. The code is on a new thread. On this thread then I can await method.
So If I clearly understood I decided to use async await for long processes which implies an order of execution on main thread.
And I use Task.run for thread to run in parrallel and process independently.
Is it the good way and is my understanding good?
Thanks,
Your understanding of async/await and Task.Run is mostly correct.
Task.Run allows you to easily run some code on a ThreadPool thread and avoid blocking current thread. Creating multiple Tasks or using Parallel class allows you take adventage of multiple CPU cores to do some work faster.
When using async/await you can do some work once your task has completed. Thanks to SynchronizationContext code after await can be executed back on your original thread, although it is not always the case. For exaple console application has no SynchronizationContext.
One important thing to remember is that async/await is great for I/O bound work while Task.Run is good for CPU bound work. Reason behind this is that when you await some I/O bound operation, like sending data over network, you don't waste any thread on just waiting for such operation to complete. You can read more about that here.
Yes, the Task.Run method is an easy way to offload work to a background thread. The worker threads are provided by the ThreadPool class. Learning a bit about this class is a good idea, to know what happens when the pool becomes starved, and what you can do if you anticipate this to happen (using the SetMinThreads proactively is an option).
Using the Task.Run is more convenient than working with Thread instances directly. Tasks have a strongly-typed Result, have an Exception property, can be awaited asynchronously, can be combined with other tasks, and can be wrapped in other tasks with extra functionality (for example wrapping a task in a cancelable wrapper.

How can I get a worker thread to execute a callback on the main UI thread?

I want to execute a number of tasks in parallel, once complete I want to execute a callback on the main UI thread. Is this possible? If so, how?
Multiple threading is not yet currenly supported, Its still under consideration, but there is support for parallel execution using Async await (just like in C#).
https://github.com/aspnet/Blazor/issues/139
https://github.com/aspnet/Blazor/issues/140

UWP handling many threads

So I am developing a UWP application that has a large number of threads. Previously I would start all the threads with System.Threading.Tasks.Task.Run(), save their thread handles to an array, then Task.WaitAll() for completion and get the results. This currently is taking too much memory though.
I have changed my code to only wait for a smaller amount of threads and copy their results out before continuing on to more of the threads. Since UWP the UWP implementation of Task does not implement IDisposable, what is the proper way to signal the framework that I am done with a task so it can be garbage collected? I would like to read out the results of the treads after a certain number of them come in and dispose of the threads resources to make space for the next threads.
Thanks so much!
Just to point out an issue which might be degrading the performance of your application: You are deliberately blocking the thread until all Tasks complete rather than actually await for them. That would make sense, if you are not performing Asynchronous work inside them, but if you are, you should definitely switch to:
Task.WhenAll rather than Task.WaitAll , such as this:
List<Tasks> tasks = new List<Tasks> { Method1(), Method2(), ... };
Task result = await Task.WhenAll(tasks);
This way, you are actually leveraging the asynchrony of your app, and you will not block the current thread until all the tasks are completed, like Task.WaitAll() does.
Since you are utilizing the Task.Run() method, instead of the Task.Factory.StartNew(), the TaskScheduler used is the default, and utilizes Threads from the Thread Pool. So you will not actually end up blocking the UI thread, but blocking many Thread Pool threads, is also not good.
Taking from Microsoft documentation, for one of the cases where Thread Pools should not be used:
You have tasks that cause the thread to block for long periods of
time. The thread pool has a maximum number of threads, so a large
number of blocked thread pool threads might prevent tasks from
starting.
Edit:
I do not need anything else but I will look in to that! Thanks! So is
there any way I can get it to run the Tasks like a FIFO with just the
API's available with the default thread pool?
You should take a look, into Continuations
A continuation is nothing else other than a task which is activated whenever it's antecedent task/tasks have completed. If you have specific tasks which you only want to execute after another task has completed you should take a look into Continuations, since they are extremely flexible, and you can actually create really complex flow of Tasks to better suit your needs.
Garbage collection on a .Net application always works the same, when a variable is not needed anymore (out of scope) it is collected.
Why do you think the threads are consuming the memory? It is much likely than the process inside the threads is the one consuming the memory.

How to get the reference of TPL task's thread in C#?

When I create a task as
Task task = Task.Factory.StartNew(() => someMethod(args));
in C# 4.0+, how can I get the reference of the thread(s) of this task?
Is it possible that the task is executed in the same thread that created the task or spawn more than one thread?
Update:
The reasons are:
I'd like to identify the task's thread in debugger (and attribute a name for it), etc.
Is created task executed always in separate thread from the one in which a task was created?
Is it one, zero or more than one thread?
Is it executed on a single and the same core?
It is important to know since, for example, I can put to sleep the main thread thinking that I am freezing the background worker
Update:
Useful answer:
Specifying a Thread's Name when using Task.StartNew
Is created task executed always in separate thread from the one in which a task was created?
No, there are certain situations in which the TPL is able to determine that the task can be executed on the same thread that created it, either because the relevant task creation option (or task scheduler) was supplied, or as an optimization because the calling thread would otherwise not have anything to do. You don't really need to worry about this though; it's not like you're going to end up blocking the UI thread because the TPL choose to execute it's code in that context. That won't happen unless you specifically indicate that it should. For all intents and purposes you can assume that this never happens (unless you force it to happen) but behind the scenes, without you ever needing to realize it, yes, it can happen.
Is it one, zero or more than one thread?
By default, tasks are executed in the thread pool. The thread pool will vary in the number of threads it contains based on the workload it's given. It will start out at one, but grow if there is sufficient need, and shrink if that need disappears. If you specify the LongRunning option, a new thread will be created just for that Task. If you specify a custom TaskScheduler, you can have it do whatever you want it to.
Is it executed on a single and the same core?
Potentially, but not assuredly.
It is important to know since, for example, I can put to sleep the main thread thinking that I am freezing the background worker
Putting the main thread to sleep will not prevent background workers from working. That's the whole point of creating the background workers, the two tasks don't stop each other from doing work. Note that if the background workers ever try to access the UI either to report progress or display results, and the UI is blocked, then they will be waiting for the UI thread to be free at that point.
You can use:
System.Threading.Thread.CurrentThread
But as said in the comments, you use the TPL to abstract threading away, so going back to this "low level" is a likely indicator of poor design.
Task.Factory.StartNew() queues the task for execution (see here). The actual thread that executes the task and when it gets executed is up to the TaskScheduler specified (the current TaskScheduler is used if none is specified).
In .Net 4 the default TaskScheduler uses the ThreadPool to execute tasks (see here) so if a ThreadPool Thread queued the task the same thread can possibly execute it later on.
The number of threads is dictated by the ThreadPool.
You shouldn't really care about which core your tasks are executed on.
Queuing a Task for execution will most likely schedule it to be executed on a ThreadPool Thread so you won't be at risk of accidentally putting the main thread to sleep

Can Task be started in NOT background thread?

I need to allow task execution after main thread exits. Is it possible?
Or I should use Thread class explicitly for this purpose?
You could write your own task scheduler to schedule tasks on non-threadpool-threads... but a simpler option would probably be to start a foreground thread which just waits for the relevant tasks to complete.
(It's hard to give a code sample as you haven't shown how the tasks are started etc, but it should be fairly easy.)

Categories