C#のTaskでデッドロックする場合/しない場合の違い
解決したいこと
下記の実験コードで、デッドロックする/しないの違いの元を教えて頂きたいです。
下記のコードが、
- ボタン押下時のハンドラの中で
Task.Delay(1000).Wait();
としたとき(①)と、Task.Runの中でawait Task.Delay(1000);
したとき(②)はデッドロックしない。 - ボタン押下時のハンドラから呼んでいる、中で
await Task.Delay(1000);
をしているメソッドを.Wait()
すると(③)、デッドロックする。
という動作をします。
using System.Threading.Tasks;
using System.Windows;
namespace WpfApp3
{
public partial class MainWindow : Window
{
public MainWindow()=> InitializeComponent();
private async Task FuncAsync()
{
await Task.Delay(1000);
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
// ①デッドロックしない
Task.Delay(1000).Wait();
// ②デッドロックしない
Task.Run(async () =>
{
await Task.Delay(1000);
}).Wait();
// ③デッドロックする
FuncAsync().Wait();
}
}
}
①も②も③も、見た目に全く同じことをしているように見えてしまうのですが、何の違いで、デッドロックする/しないが変化するのでしょうか?
環境
- VisualStudio 2022
- .NET6/WPF
試したことなど
以前、Taskの動きについて調べて記事を書かせていただいたとき(コチラ)には、下記のような理解をしていました。
.Wait()
をして、呼び出し元のスレッドが止まってしまうため、
awaitをして呼び出し元のスレッドに処理を一旦戻そうとしたときに、
戻った先が止まっているためにその後動けなくなってデッドロックする、という理解です。
その理解で行くと、②については、Task.Runが.Wait()
しているのでその時点で呼び出し元のUIスレッドが止まって、Task.Runの中のawaitの中で呼び出し元のメインスレッドに戻ろうとするので、デッドロックしそうなものだと思うのですが、、、
皆様の知恵を貸していただけると幸いです。よろしくお願いします。