2

MDBG サンプルを使用してマネージド .NET デバッガーを作成しています。

簡単な非同期の例を考えてみましょう:

1:          private async void OnClick(EventArgs args){
2:              var obj = new SomeClass();
3:              bool res = await StaticHelper.DoSomeAsyncStuff();
4:              if(res){
5:                  Debug.WriteLine("result is True");
6:              }
7:              else{
8:                  Debug.WriteLine("result is False");
9:              }
10:             someField = obj.Name + "is:" + res.ToString();
11:         }

12:         public static async Task<bool> DoSomeAsyncStuff(){
13:             await Task.Delay(5000);
14:             return true;
15:         }

デバッガーでこのコードをデバッグすると、2 つの大きな問題が発生します。

  1. ローカル変数名が変更されている (CS$4$0000、CS$0$0001 など) か、見つからない (デバッガーのローカル変数で obj が見つからない)
  2. ステッピングは予期せぬ動作をします: a) 3 行目の ステッピングなどは、通常、評価が完了するのを待ってから 4 行目に移動する必要があります。しかし、代わりにデバッガーは 13 行目にジャンプし、そこからステップ実行を続けます。ビデオでのステップオーバー動作

    b) 3 行目のステップ インなどは、各行を ステップ インする必要があります: 3 行目 -> 12 行目 -> 13 行目 (しばらくハング) -> 14 行目 -> 15 行目 -> 4 行目。 13 行目では、デバッガーが評価結果を待機すると予想されますが、何らかの理由で 3 行目に進みます。その後、デバッガーは結果を待機し、実行は期待どおりに続行されます。ビデオでのステップイン動作

    c)応答を待っている間にスケジュールされた他の作業がある場合、デバッガーはそのコードに切り替えます。たとえば、応答の待機中に経過したタイマーがある場合、13 行目以降の評価はそのタイマー コードで続行されます。代わりに、ビジュアルスタジオのように、デバッガーが現在のスコープに固執し、完全に実行されるまで離れないことを期待します。ビデオでの並列動作

これらの問題の原因を部分的に理解しています。コンパイラは、ロジックが MoveNext メソッド内にカプセル化されているネストされた構造体によって表されるステート マシンを作成します。少なくとも、a) と b) の場合に期待するようにステッピングが機能しない理由を説明しています。シンボルなしでいくつかのコードにステップインするとき (コンパイラによって生成されたコードのシンボルがない場合)、自分のコードに到達するために 1 つまたは複数のステップを実行しています。@Brian Reichleがこの関連する質問で提案したのは解決策です

ローカル変数名の変更については、 Stack Spilling("What's going" chapter)が原因であると思いました。しかし、ILDASM を使用してアセンブリを分析すると、生成された構造体の t__stack フィールドに何も保存されていません。したがって、非同期メソッドの変数名が永続化されない理由は推測できません。

それにもかかわらず、VisualStudio はこれらすべての問題を何らかの方法で回避しています。

では、管理された .net デバッガーは、async/await シナリオでステッピングとローカル変数の解決をどのように処理する必要があるのでしょうか?

この背後には多くの実装コードがありますが、どの部分を表示するのが適切かわかりません...

4

0 に答える 0