やりたいこと
Taskの中でawaitをつけたTask、つけてないTaskを走らせて、どういう動作をするか確認したい。
Thread MainThread;
Thread TaskThread;
Thread TaskThread2;
Thread TaskThread3;
bool endflag = false;
private async void Button_Click_7(object sender, RoutedEventArgs e)
{
MainThread = Thread.CurrentThread;
distThreadStatus("■Mainスレッド(Taskスレッド1開始前)");
endflag = false;
await Task.Run(() =>
{
TaskThread = Thread.CurrentThread;
distThreadStatus("■Taskスレッド1開始");
Task.Run(async () =>
{
TaskThread2 = Thread.CurrentThread;
distThreadStatus("■Taskスレッド2開始");
await Task.Run(() =>
{
TaskThread3 = Thread.CurrentThread;
distThreadStatus("■Taskスレッド3 Sleep前");
Thread.Sleep(2000);
distThreadStatus("■Taskスレッド3 Sleep後");
endflag = true;
});
distThreadStatus("■Taskスレッド2抜ける");
});
while (!endflag)
{
Thread.Sleep(100);
Console.WriteLine("Looping..");
}
distThreadStatus("■Taskスレッド1抜ける");
});
distThreadStatus("■Taskスレッド終了後");
}
private void Button_Click_5(object sender, RoutedEventArgs e)
{
distThreadStatus("■メインスレッド(別ボタン押下)");
}
void distThreadStatus(string title)
{
Console.WriteLine(title);
Console.WriteLine($" MainThreadの状態(ID:{MainThread.ManagedThreadId}):{MainThread.ThreadState}");
if (TaskThread != null) Console.WriteLine($" TaskThreadの状態(ID:{TaskThread.ManagedThreadId}):{TaskThread.ThreadState}");
if (TaskThread2 != null) Console.WriteLine($" TaskThread2の状態(ID:{TaskThread2.ManagedThreadId}):{TaskThread2.ThreadState}");
if (TaskThread3 != null) Console.WriteLine($" TaskThread3の状態(ID:{TaskThread3.ManagedThreadId}):{TaskThread3.ThreadState}");
}
■Mainスレッド(Taskスレッド開始前)
MainThreadの状態(ID:1):Running
■Taskスレッド開始
MainThreadの状態(ID:1):Running
TaskThreadの状態(ID:4):Background
■Taskスレッド2開始
MainThreadの状態(ID:1):Running
TaskThreadの状態(ID:4):Background, WaitSleepJoin
TaskThread2の状態(ID:3):Background
■Taskスレッド3 Sleep前
MainThreadの状態(ID:1):Running
TaskThreadの状態(ID:4):Background, WaitSleepJoin
TaskThread2の状態(ID:3):Background
TaskThread3の状態(ID:7):Background
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
Looping..
■Taskスレッド3 Sleep後
MainThreadの状態(ID:1):Running
TaskThreadの状態(ID:4):Background, WaitSleepJoin
TaskThread2の状態(ID:3):Background
TaskThread3の状態(ID:7):Background
■Taskスレッド2抜ける
MainThreadの状態(ID:1):Running
TaskThreadの状態(ID:4):Background, WaitSleepJoin
TaskThread2の状態(ID:3):Background
TaskThread3の状態(ID:7):Background
Looping..
■Taskスレッド1抜ける
MainThreadの状態(ID:1):Running
TaskThreadの状態(ID:4):Background
TaskThread2の状態(ID:3):Background
TaskThread3の状態(ID:7):Background
■Taskスレッド終了後
MainThreadの状態(ID:1):Running
TaskThreadの状態(ID:4):Background
TaskThread2の状態(ID:3):Background
TaskThread3の状態(ID:7):Background
実験結果と理解したことメモ
- asyncを付けてるメソッドは、
- 自分は非同期処理を行うので、処理完了していなくても下に抜けていきますよ、ということを表明している。
- また、自分の処理の完了を待ちたかったら、自分に「await」を付けてくださいよ、ということを表明している。
- Taskの中でawaitが出てくると、そのawaitがついているTaskが終わるまで待つ。
- そのTaskと並行して、呼び元のasyncのついていないスレッドは処理を続けている。(ここでいうところの、
■Taskスレッド1
は、■Taskスレッド2
とその中の■Taskスレッド3
が開始してawaitに入っても処理が続けて実行されている) - UIが固まらないのは、ここでいうところのボタン押下時のasyncがついたハンドラ「Button_Click_7」の完了を待たずに、UIの自分の処理をしているから。(UI的には、Button_Click_7の中の処理は、投げっぱなしで完了を待たなくてよい処理ということ)
たぶん、UIが固まらないのは、ボタンのハンドラの中の処理と、UIのその他の処理が、ここでいうところの■Taskスレッド1
と■Taskスレッド2
のようになっているからではないか。
(Taskスレッド1(の中のwhile文)がUIの画面処理にあたり、Taskスレッド2が、投げっぱなしにしたハンドラの処理にあたるのでは。)