次の方法で共有


マルチスレッド アプリケーションのデバッグを始める (C#、Visual Basic、C++)

Visual Studio には、マルチスレッド アプリケーションのデバッグに役立つツールとユーザー インターフェイス要素がいくつか用意されています。 このチュートリアルでは、スレッド マーカー、 [並列スタック] ウィンドウ、 [並列ウォッチ] ウィンドウ、条件付きブレークポイントの使用方法と、ブレークポイントのフィルター方法について説明します。 このチュートリアルを完了すると、マルチスレッド アプリケーションをデバッグするための Visual Studio の機能を理解できます。

次の 2 つの記事では、他のマルチスレッド デバッグ ツールの使用に関する追加情報が提供されています。

最初の手順は、マルチスレッド アプリケーション プロジェクトを作成することです。

マルチスレッド アプリ プロジェクトを作成する

  1. Visual Studio を起動し、新しいプロジェクトを作成します。

    スタート ウィンドウが開いていない場合は、[ファイル]>[スタート ウィンドウ] を選択します。

    スタート ウィンドウで、 [新しいプロジェクトの作成] を選択します。

    [新しいプロジェクトの作成] ウィンドウで、検索ボックスに「コンソール」と入力またはタイプします。 次に、[言語] の一覧から [C#][C++] 、または [Visual Basic] を選択し、[プラットフォーム] の一覧から [Windows] を選択します。

    言語およびプラットフォームのフィルターを適用してから、.NET または C++ 用の [コンソール アプリ] テンプレートを選択して、[次へ] を選択します。

    注意

    正しいテンプレートが表示されない場合は、 [ツール]>[ツールと機能を取得...] に移動して、Visual Studio インストーラーを開きます。 [.NET デスクトップ開発] ワークロードまたは [C++ によるデスクトップ開発] ワークロードを選択し、 [変更] を選択します。

    [新しいプロジェクトの構成] ウィンドウの [プロジェクト名] ボックスに「MyThreadWalkthroughApp」と入力します。 次に、 [次へ] または [作成] を選択します (いずれかのオプションを使用できます)。

    .NET Core または .NET 5+ プロジェクトの場合は、推奨されるターゲット フレームワークまたは .NET 8 を選択し、[作成] を選択します。

    新しいコンソール プロジェクトが表示されます。 プロジェクトが作成されると、ソース ファイルが表示されます。 選択した言語に応じて、ソース ファイルの名前は Program.csMyThreadWalkthroughApp.cppModule1.vb などとなります。

  2. ソース ファイルに表示されるコードを削除し、次の更新済みコードに置き換えます。 コード構成に適したスニペットを選択します。

    using System;
    using System.Threading;
    
    public class ServerClass
    {
    
        static int count = 0;
        // The method that will be called when the thread is started.
        public void InstanceMethod()
        {
            Console.WriteLine(
                "ServerClass.InstanceMethod is running on another thread.");
    
            int data = count++;
            // Pause for a moment to provide a delay to make
            // threads more apparent.
            Thread.Sleep(3000);
            Console.WriteLine(
                "The instance method called by the worker thread has ended. " + data);
        }
    }
    
    public class Simple
    {
        public static void Main()
        {
            for (int i = 0; i < 10; i++)
            {
                CreateThreads();
            }
        }
        public static void CreateThreads()
        {
            ServerClass serverObject = new ServerClass();
    
            Thread InstanceCaller = new Thread(new ThreadStart(serverObject.InstanceMethod));
            // Start the thread.
            InstanceCaller.Start();
    
            Console.WriteLine("The Main() thread calls this after "
                + "starting the new InstanceCaller thread.");
    
        }
    }
    
  3. [ファイル] メニューの [すべてを保存] をクリックします。

  4. (Visual Basic のみ) ソリューション エクスプローラー (右ペイン) でプロジェクト ノードを右クリックし、 [プロパティ] を選択します。 [アプリケーション] タブで、 [スタートアップ オブジェクト][シンプル] に変更します。

マルチスレッド アプリをデバッグする

  1. ソース コード エディターで、次のコード スニペットを探します。

    Thread.Sleep(3000);
    Console.WriteLine();
    
  2. Thread.Sleep または C++ の場合は std::this_thread::sleep_for ステートメントの左側の余白を左クリックして、新しいブレークポイントを挿入します。

    余白の赤い円は、ブレークポイントがこの場所に設定されていることを示します。

  3. [デバッグ] メニューの [デバッグの開始] (F5 キー) を選択します。

    Visual Studio によってソリューションがビルドされ、デバッガーがアタッチされた状態でアプリの実行が開始されて、ブレークポイントでアプリが停止します。

  4. ソース コード エディターで、ブレークポイントが含まれている行を探します。

スレッド マーカーを検出する

  1. [デバッグ] ツール バーで、[ソースのスレッドを表示] ボタン ソースのスレッドを表示 を選択します。

  2. F11 キーを 2 回押してデバッガーを進める。

  3. ウィンドウ左端の余白に注目します。 この行では、2 本の撚糸に似た "スレッド マーカー" アイコン スレッド マーカー に注目してください。 スレッド マーカーは、スレッドが停止している位置を示します。

    スレッド マーカーは、ブレークポイントによって部分的に隠されている場合があります。

  4. スレッド マーカーの上にポインターを置きます。 データヒントには、停止されている各スレッドの名前とスレッド ID 番号が表示されます。 この場合、名前はおそらく <noname> になります。

    DataTip 内のスレッド ID のスクリーンショット。

  5. スレッド マーカーを選択すると、ショートカット メニューに使用可能なオプションが表示されます。

スレッドの場所を表示する

[並列スタック] ウィンドウでは、[スレッド] ビューと (タスク ベースのプログラミングの場合) [タスク] ビューを切り替えることができ、各スレッドの呼び出し履歴情報を表示できます。 このアプリでは、[スレッド] ビューを使用できます。

  1. [デバッグ]>[Windows]>[並列スタック] を選択して、 [並列スタック] ウィンドウを開きます。 次のような内容が表示されます。 正確な情報は、各スレッドの現在の位置、ハードウェア、プログラミング言語によって異なります。

    並行スタック ウィンドウのスクリーンショット。

    この例では、左から右に、マネージド コードに関する次の情報が表示されています。

    • 現在のスレッド (黄色の矢印) が に ServerClass.InstanceMethod が入力されました。 ServerClass.InstanceMethod にカーソルを合わせると、スレッドのスレッド ID とスタック フレームを表示できます。
    • スレッド 31724 は、スレッド 20272 が所有するロックを待機しています。
    • [外部コード] でメイン スレッド (左側) が停止しました。[外部コードの表示] を選択すると詳細を確認できます。

    並列スタック ウィンドウ

    この例では、左から右に、マネージド コードに関する次の情報が表示されています。

    • メイン スレッド (左側) は Thread.Start で停止しています。ここでは、停止ポイントはスレッド マーカー アイコン スレッド マーカー で識別されます。
    • 2 つのスレッドが ServerClass.InstanceMethod に入っています。1 つは現在のスレッド (黄色の矢印) で、もう一方のスレッドは Thread.Sleep で停止しています。
    • 新しいスレッド (右側) も開始していますが、ThreadHelper.ThreadStart で停止されています。
  2. リスト ビューでスレッドを表示するには、[>Windows >スレッドデバッグ] を選択します。

    スレッド ウィンドウのスクリーンショット。

    このビューでは、スレッド 20272 がメイン スレッドであり、現在は外部コード (特に System.Console.dll) に配置されていることを簡単に確認できます。

    注意

    [スレッド] ウィンドウの使用方法の詳細については、「チュートリアル: マルチスレッド アプリケーションをデバッグする」を参照してください。

  3. [並列スタック] ウィンドウまたは [スレッド] ウィンドウでエントリを右クリックし、ショートカット メニューで使用可能なオプションを表示します。

    これらの右クリック メニューからさまざまなアクションを実行できます。 このチュートリアルでは、並列ウォッチ ウィンドウ (次のセクション) でこれらの詳細について詳しく説明します。

変数にウォッチを設定する

  1. [デバッグ]>[Windows]>[並列ウォッチ]>[並列ウォッチ 1] を選択して、 [並列ウォッチ] ウィンドウを開きます。

  2. <Add Watch> というテキストが表示されているセル (または 4 番目の列の空のヘッダー セル) を選択し、「data」と入力します。

    各スレッドのデータ変数の値がウィンドウに表示されます。

  3. <Add Watch> というテキストが表示されているセル (または 5 番目の列の空のヘッダー セル) を選択し、「count」と入力します。

    各スレッドの count 変数の値がウィンドウに表示されます。 この情報がまだ表示されない場合は、F11 キーを数回押して、デバッガーでスレッドの実行を進めてください。

    [並列ウォッチ] ウィンドウ

  4. ウィンドウ内のいずれかの行を右クリックし、使用可能なオプションを表示します。

スレッドに対するフラグの設定と設定解除を行う

スレッドにフラグを付けることで、重要なスレッドを追跡し、他のスレッドを無視することができます。

  1. [並列ウォッチ] ウィンドウで、Shift キーを押しながら複数の行を選択します。

  2. 右クリックして、 [フラグ] を選択します。

    選択したすべてのスレッドにフラグが設定されます。 これで、フィルター処理して、フラグが設定されたスレッドのみを表示できるようになります。

  3. [並列ウォッチ] ウィンドウで、[フラグが設定されたスレッドのみを表示] ボタン フラグが設定されたスレッドを表示する を選択します。

    フラグが設定されたスレッドのみが一覧に表示されます。

    ヒント

    いくつかのスレッドにフラグを設定したら、コード エディターでコード行を右クリックし、 [フラグが設定されたスレッドをカーソル行の前まで実行] を選択できます。 フラグが設定されたすべてのスレッドが到達するコードを選択してください。 Visual Studio により選択したコード行でスレッドが一時停止されるので、スレッドを凍結および凍結解除することにより、実行の順序を簡単に制御できます。

  4. すべてのスレッドを表示モードに戻すには、 [フラグが設定されたスレッドのみを表示] ボタンをもう一度選択します。

  5. スレッドのフラグを解除するには、 [並列ウォッチ] ウィンドウでフラグが設定されたスレッドを 1 つ以上右クリックして、 [フラグ解除] を選択します。

スレッドの実行を凍結および凍結解除する

ヒント

スレッドを凍結および凍結解除 (一時停止と再開) して、スレッドによる処理の実行順序を制御できます。 これは、デッドロックや競合状態など、同時実行の問題を解決するのに役立ちます。

  1. [並列ウォッチ] ウィンドウですべての行を選択し、右クリックして、 [凍結] を選択します。

    各行の 2 番目の列に、一時停止アイコンが表示されます。 一時停止アイコンは、スレッドが凍結されていることを示します。

  2. 1 行だけを選択し、他のすべての行の選択を解除します。

  3. 行を右クリックして、 [凍結解除] を選択します。

    この行の一時停止アイコンが消え、スレッドが凍結されなくなったことが示されます。

  4. コード エディターに切り替えて、F11 キーを押します。 凍結されていないスレッドだけが実行されます。

    アプリで新しいスレッドがインスタンス化される場合があります。 新しいスレッドはすべて、フラグを設定されておらず、凍結されていません。

条件付きブレークポイントを使用して 1 つのスレッドを追跡する

デバッガーで 1 つのスレッドの実行を追跡すると、便利な場合があります。 これを行う 1 つの方法は、関心のないスレッドを凍結することです。 特定のバグを再現する場合など、シナリオによっては、他のスレッドを凍結せずに 1 つのスレッドを追跡することが必要になる場合があります。 他のスレッドを凍結せずにスレッドを追跡するには、関心のあるスレッド以外のコードに割り込まないようにする必要があります。 これを行うには、条件付きブレークポイントを設定します。

スレッド名やスレッド ID など、さまざまな条件でブレークポイントを設定できます。 スレッドごとに一意であることがわかっているデータで条件を設定すると、便利な場合があります。 このアプローチは、特定のスレッドよりも特定のデータ値に関心がある場合、デバッグ時に一般的に使用されます。

  1. 前に作成したブレークポイントを右クリックし、 [条件] を選択します。

  2. [ブレークポイント設定] ウィンドウで、条件式に「data == 5」と入力します。

    条件付きブレークポイント

    ヒント

    特定のスレッドの方に関心がある場合は、条件にスレッド名またはスレッド ID を使用します。 これを行うには、 [ブレークポイント設定] ウィンドウで、 [条件式] ではなく [フィルター] を選択し、フィルターのヒントに従います。 スレッド ID はデバッガーを再起動すると変化するため、アプリ コードでスレッドに名前を付けることができます。

  3. [ブレークポイント設定] ウィンドウを閉じます。

  4. [再起動] アプリの再起動 ボタンを選択して、デバッグ セッションを再開します。

    データ変数の値が 5 になったスレッドで、コードに割り込みます。 [並列ウォッチ] ウィンドウで、現在のデバッガー コンテキストを示す黄色の矢印を探します。

  5. これで、コードをステップオーバー (F10 キー) およびステップイン (F11 キー) して、1 つのスレッドの実行を追跡できます。

    ブレークポイントの条件がスレッドに対して一意であり、デバッガーが他のスレッドで他のブレークポイントにヒットしない場合 (無効にすることが必要な場合があります)、他のスレッドに切り替えずに、コードのステップオーバーやステップインを行うことができます。

    Note

    デバッガーを進めると、すべてのスレッドが実行されます。 ただし、他のスレッドのいずれかがブレークポイントにヒットしない限り、デバッガーが他のスレッドのコードに割り込むことはありません。