1
3

More than 5 years have passed since last update.

【C#】【Task】Taskでマルチスレッドするときの、async/awaitのある時、ない時の処理の実行順の実験2

Last updated at Posted at 2019-04-18

やりたいこと

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が、投げっぱなしにしたハンドラの処理にあたるのでは。)

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3