Reputation: 64205
I know that the TPL is task-oriented, while the classic threading model is worker-oriented. Tasks let you focus primarily on what problem you want to solve instead of on the mechanics of how it will get done. But I am still a bit confused when it comes to thread and task relationship.
Below is a demo code:
namespace AsyncUnderTheHood
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main Start : {0}", Thread.CurrentThread.ManagedThreadId);
AwaitTest();
Console.WriteLine("Main End : {0}", Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}
public static void DoWork()
{
Console.WriteLine("DoWork Start: {0}", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(5000);
Console.WriteLine("DoWork End: {0}", Thread.CurrentThread.ManagedThreadId);
}
public async static void AwaitTest()
{
Console.WriteLine("AwaitTest Start : {0}", Thread.CurrentThread.ManagedThreadId);
Task t = new Task(DoWork);
t.Start();
await t;
Console.WriteLine("AwaitTest Done : {0}", Thread.CurrentThread.ManagedThreadId);
}
}
}
The output is like this:
Main Start : 1
AwaitTest Start : 1 <------------ A
DoWork Start: 3
Main End : 1
DoWork End: 3
AwaitTest Done : 3 <------------ B
My question is, why A and B is on different thread?
The same method is executed on different threads, will this cause issue when thread affinity is important?
Upvotes: 3
Views: 176
Reputation: 456457
This blog post has a good description of how TPL uses multiple task queues with work stealing to layer on top of the existing thread pool for optimum performance.
Upvotes: 0
Reputation: 244777
why A and B is on different thread?
First, if your Task
s are scheduled by the default scheduler, then there is no guarantee which Thread
will a Task
run on. And the parts of AwaitTest()
are executed separately, so there is no guarantee they will run on the same thread.
Second, the default scheduler uses the ThreadPool
to execute Task
s. And the first part of each async
method runs synchronously. In your case, this means the first part of AwaitTest()
will run on the main thread and the second part will run on some ThreadPool
thread. So, you're actually guaranteed that they won't run on the same thread.
will this cause issue when thread affinity is important?
It certainly could. But it will work correctly in the most common case where thread affinity is important: GUI programming. This is because GUI applications have SynchronizationContext
set, which means that if the first part of an async
method runs on the UI thread, the second part will run there too (unless you disable this by using ConfigureAwait(false)
).
But in other cases, it will cause problems. For example, take the following code:
Monitor.Enter(lockObject);
await someTask;
Monitor.Exit(lockObject);
This code wouldn't work in a console application (Exit()
will most likely throw SynchronizationLockException
), because the Exit()
can run on different thread than Enter()
.
Upvotes: 3
Reputation: 35881
You've asked the system to "await" a task. What you're really asking is that the thread that invoked await
should continue running and everything after the await
is a "continuation" that will get run asynchronously when the task is done. Since there's no "message pump" in a console application, there's no easy way to marshal back to the "main" thread and thus the continuation just continues on with the asynchronous Task
's thread. If you performed the same test in a WinForm or WPF application, the continuation would run on the UI thread.
Upvotes: 1