やりたいこと
Taskでawaitしている個所に.ConfigureAwait(false)
を付けると、その後の処理で、アプリが落ちたりすることがある。なんでなのか?調べたい。
わかったこと
.ConfigureAwait(false)
を付けたときとつけてないときで、処理が行われるスレッドが違う。
コードで見る
おちない場合
下記のようなコードがあるとして、
using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using System.Windows; namespace WpfApp2 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void Button_Click(object sender, RoutedEventArgs e) { DispThread(1); await Task.Run(async () => { DispThread(2); });//.ConfigureAwait(false); // ★この「.ConfigureAwait(false);」 DispThread(3); bt.Content = "abc"; } private void DispThread(int id) { Debug.WriteLine($" {id}:{Thread.CurrentThread.ManagedThreadId}"); } } }
つけてないと、こうなる。
開始冒頭:スレッドID=1
タスク内:スレッドID=9
タスク後:スレッドID=1
※スレッドIDは、実行都度異なるかもしれない。
タスク後は、UIのスレッドに戻るので、普通に画面更新の処理bt.Content = "abc";
ができる。
落ちる場合
private async void Button_Click(object sender, RoutedEventArgs e) { DispThread(1); await Task.Run(async () => { DispThread(2); }).ConfigureAwait(false); // ★この「.ConfigureAwait(false);」 DispThread(3); bt.Content = "abc"; }
これを実行すると、下記の例外で落ちる。
この場合のスレッド番号は下記になる。
開始冒頭:スレッドID=1
タスク内:スレッドID=9
タスク後:スレッドID=9
で、なぜ落ちるかというと、UIの更新は、UIのスレッド(スレッドID=1)でしか行えず、別のスレッドで行うと、上記の例外が起きる。
タスクを.ConfigureAwait(false);
すると、UIスレッドに戻らずに、Taskを実行したままのスレッドで続きをやるようになるので、UI更新を含むタスク後のスレッドが、UIスレッドではないスレッドで実行されるようになり、落ちる。