下記のコードは、ボタン5を押すと子タスクと孫タスクが起動して、子タスクが、孫Taskのj>7のFalseを待って、終了する積りで書いたものです。
Dim tokenSource As New CancellationTokenSource
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
tokenSource.Cancel()
End Sub
Private Async Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
tokenSource = New CancellationTokenSource
Dim token As CancellationToken = tokenSource.Token
Debug.Print($"StartTask ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
Try
Await Task.Run(
Async Sub()
Dim i As Integer = 0
Debug.Print($"子Task ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
Dim 孫Task As Task = Task.Run(
Sub()
Dim j As Integer = 0
Debug.Print($"孫子Task ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
While j < 7
If token.IsCancellationRequested Then
Debug.Print("孫Taskは、停止しました。")
Exit While
End If
Thread.Sleep(500) '0.5秒待つ
Debug.Print($"孫TaskCount:{j}")
j += 1
End While
End Sub)
While i < 5
If token.IsCancellationRequested Then
Debug.Print("子Taskは、停止しました。")
Exit While
End If
Thread.Sleep(500) '0.5秒待つ
Debug.Print($"子TaskCount:{i}")
i += 1
End While
Await 孫Task
End Sub)
Finally
tokenSource.Dispose()
End Try
Debug.Print($"FinishTask ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
End Sub
ところが、動かしてみると、どうも子タスクは、孫タスクの終了を待ってくれないようです。Awaitで待機しているにもかかわらず。
なぜでしょうか?
StartTask ID: スレッド:1
子Task ID:1 スレッド:3
孫子Task ID:3 スレッド:4
孫TaskCount:0
子TaskCount:0
(省略)
孫TaskCount:4
子TaskCount:4
FinishTask ID: スレッド:1
孫TaskCount:5
孫TaskCount:6
一方、ボタン2を押すと見かけ上は、なんとなく動いているようにも見えるような結果が得られましたが、根本的な問題解決になっていないことは理解しています。また、Task.Runでtokenを渡していませんが、現時点では、意図的なものです。
StartTask ID: スレッド:1
子Task ID:1 スレッド:3
孫子Task ID:3 スレッド:4
子TaskCount:0
孫TaskCount:0
孫TaskCount:1
子TaskCount:1
子TaskCount:2
子Taskは、停止しました。
孫TaskCount:2
孫Taskは、停止しました。
FinishTask ID: スレッド:1
子タスクが、孫タスクを待つようにするには、どのようにすれば良いのでしょうか?
詳しい方いらっしゃいましたら、御指南頂けないでしょうか?宜しくお願い致します。
> でも、どこで、Task(多分?孫Task?)がReturnされるのでしょうか?
Awaitを含むFunctionは、コンパイラが暗黙にTaskを返却するようなコードにコンパイルします。
Async Function Hoge() As Task
Debug.WriteLine("enter") ' 一度Awaitするまでは同期的に実行される
Await Task.Delay(1000) ' Task.Delayおよびそれ以降の処理がTaskとして返値になる
Debug.WriteLine("exit")
End Function
> なぜ?Functionなのでしょうか?
Subは返値なし、Functionは返値ありです。
Sub Hoge() As Taskとは書けません。
Taskを返したいならFunctionでなければなりません。
Async Subと書くケースはほぼイベントハンドラのみになるはずで、
ほとんどの場合Async Functionになります。