Freigeben über


Exemplarische Vorgehensweise: Debuggen einer parallelen Anwendung in Visual Studio (C#, Visual Basic, C++)

In dieser exemplarischen Vorgehensweise wird gezeigt, wie Sie die Fenster "Parallele Aufgaben " und "Parallele Stapel" verwenden, um eine parallele Anwendung zu debuggen. Diese Fenster helfen Ihnen, das Laufzeitverhalten von Code zu verstehen und zu überprüfen, der die Parallelbibliothek (Task Parallel Library, TPL) oder die Parallelitätslaufzeit verwendet. Diese Anleitung enthält Beispielcode mit integrierten Haltepunkten. Nachdem der Code unterbrochen wurde, zeigt die exemplarische Vorgehensweise, wie Sie die Fenster Parallelaufgaben und Parallelstapel verwenden, um den Code zu untersuchen.

In dieser exemplarischen Vorgehensweise werden die folgenden Aufgaben erläutert:

  • So zeigen Sie die Aufrufstapel aller Threads in einer Ansicht an.

  • So zeigen Sie die Liste der System.Threading.Tasks.Task Instanzen an, die in Ihrer Anwendung erstellt werden.

  • So zeigen Sie die tatsächlichen Aufrufstapel von Aufgaben anstelle von Threads an.

  • So navigieren Sie zum Code aus den Fenstern "Parallele Aufgaben" und "Parallele Stapel".

  • Wie die Fenster mit der Skalierung durch Gruppierung, Zoomen und andere verwandte Funktionen umgehen.

Voraussetzungen

Bei dieser exemplarischen Vorgehensweise wird davon ausgegangen, dass "Nur Mein Code " aktiviert ist (standardmäßig in neueren Versionen von Visual Studio aktiviert). Wählen Sie im Menü "Extras" die Option "Optionen" aus, erweitern Sie den Knoten "Debuggen", wählen Sie "Allgemein" und dann "Nur mein Code aktivieren" (nur verwaltet) aus. Wenn Sie dieses Feature nicht festlegen, können Sie diese exemplarische Vorgehensweise weiterhin verwenden, aber Ihre Ergebnisse unterscheiden sich möglicherweise von den Abbildungen.

C#-Beispiel

Wenn Sie das C#-Beispiel verwenden, wird in dieser exemplarischen Vorgehensweise auch davon ausgegangen, dass externer Code ausgeblendet ist. Wenn Sie umschalten möchten, ob externer Code angezeigt wird, klicken Sie mit der rechten Maustaste auf die Kopfzeile der Namenstabelle des Fensters "Aufrufliste ", und aktivieren oder deaktivieren Sie dann " Externer Code anzeigen". Wenn Sie dieses Feature nicht festlegen, können Sie diese exemplarische Vorgehensweise weiterhin verwenden, aber Ihre Ergebnisse unterscheiden sich möglicherweise von den Abbildungen.

C++-Beispiel

Wenn Sie das C++-Beispiel verwenden, können Sie Verweise auf externen Code in diesem Artikel ignorieren. Externer Code gilt nur für das C#-Beispiel.

Abbildungen

Die Abbildungen in diesem Artikel werden auf einem Computer mit vier Kernen aufgezeichnet, auf dem das C#-Beispiel ausgeführt wird. Obwohl Sie andere Konfigurationen verwenden können, um diese exemplarische Vorgehensweise abzuschließen, unterscheiden sich die Illustrationen möglicherweise von dem, was auf Ihrem Computer angezeigt wird.

Erstellen des Beispielprojekts

Der Beispielcode in dieser exemplarischen Vorgehensweise ist für eine Anwendung vorgesehen, die nichts tut. Der Zweck der Übung besteht darin, zu verstehen, wie sie die Toolfenster zum Debuggen einer parallelen Anwendung verwenden.

  1. Öffnen Sie Visual Studio, und erstellen Sie ein neues Projekt.

    Wenn das Startfenster nicht geöffnet ist, wählen Sie Datei>Startfensteraus.

    Wählen Sie im Startfenster " Neues Projekt" aus.

    Wählen Sie im Startfenster Neues Projekt erstellen aus.

    Geben Sie im Fenster Neues Projekt erstellen im Suchfeld Konsole ein. Wählen Sie als Nächstes C#, C++ oder Visual Basic aus der Liste "Sprache" aus, und wählen Sie dann Windows aus der Liste "Plattform" aus.

    Nachdem Sie die Sprach- und Plattformfilter angewendet haben, wählen Sie die Konsolen-App für .NET Core oder C++ und dann "Weiter" aus.

    Hinweis

    Wenn die richtige Vorlage nicht angezeigt wird, wechseln Sie zu Tools>»Tools und Features abrufen«, wodurch das Visual Studio-Installationsprogramm geöffnet wird. Wählen Sie die .NET-Desktopentwicklung oder Desktopentwicklung mit C++ -Workload aus, und wählen Sie dann "Ändern" aus.

    Geben Sie im Fenster " Neues Projekt konfigurieren " einen Namen ein, oder verwenden Sie den Standardnamen im Feld "Projektname ". Wählen Sie dann "Weiter" oder " Erstellen" aus, je nachdem, welche Option verfügbar ist.

    Wählen Sie für .NET Core entweder das empfohlene Zielframework oder .NET 8 aus, und wählen Sie dann Erstellen aus.

    Ein neues Konsolenprojekt wird angezeigt. Nachdem das Projekt erstellt wurde, wird eine Quelldatei angezeigt.

  2. Öffnen Sie die Codedatei .cpp, .cs oder .vb im Projekt. Löschen Sie den Inhalt, um eine leere Codedatei zu erstellen.

  3. Fügen Sie den folgenden Code für die ausgewählte Sprache in die leere Codedatei ein.

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Diagnostics;
    
    class S
    {
      static void Main()
      {
        pcount = Environment.ProcessorCount;
        Console.WriteLine("Proc count = " + pcount);
        ThreadPool.SetMinThreads(4, -1);
        ThreadPool.SetMaxThreads(4, -1);
    
        t1 = new Task(A, 1);
        t2 = new Task(A, 2);
        t3 = new Task(A, 3);
        t4 = new Task(A, 4);
        Console.WriteLine("Starting t1 " + t1.Id.ToString());
        t1.Start();
        Console.WriteLine("Starting t2 " + t2.Id.ToString());
        t2.Start();
        Console.WriteLine("Starting t3 " + t3.Id.ToString());
        t3.Start();
        Console.WriteLine("Starting t4 " + t4.Id.ToString());
        t4.Start();
    
        Console.ReadLine();
      }
    
      static void A(object o)
      {
        B(o);
      }
      static void B(object o)
      {
        C(o);
      }
      static void C(object o)
      {
        int temp = (int)o;
    
        Interlocked.Increment(ref aa);
        while (aa < 4)
        {
          ;
        }
    
        if (temp == 1)
        {
          // BP1 - all tasks in C
          Debugger.Break();
          waitFor1 = false;
        }
        else
        {
          while (waitFor1)
          {
            ;
          }
        }
        switch (temp)
        {
          case 1:
            D(o);
            break;
          case 2:
            F(o);
            break;
          case 3:
          case 4:
            I(o);
            break;
          default:
            Debug.Assert(false, "fool");
            break;
        }
      }
      static void D(object o)
      {
        E(o);
      }
      static void E(object o)
      {
        // break here at the same time as H and K
        while (bb < 2)
        {
          ;
        }
        //BP2 - 1 in E, 2 in H, 3 in J, 4 in K
        Debugger.Break();
        Interlocked.Increment(ref bb);
    
        //after
        L(o);
      }
      static void F(object o)
      {
        G(o);
      }
      static void G(object o)
      {
        H(o);
      }
      static void H(object o)
      {
        // break here at the same time as E and K
        Interlocked.Increment(ref bb);
        Monitor.Enter(mylock);
        while (bb < 3)
        {
          ;
        }
        Monitor.Exit(mylock);
    
    
        //after
        L(o);
      }
      static void I(object o)
      {
        J(o);
      }
      static void J(object o)
      {
        int temp2 = (int)o;
    
        switch (temp2)
        {
          case 3:
            t4.Wait();
            break;
          case 4:
            K(o);
            break;
          default:
            Debug.Assert(false, "fool2");
            break;
        }
      }
      static void K(object o)
      {
        // break here at the same time as E and H
        Interlocked.Increment(ref bb);
        Monitor.Enter(mylock);
        while (bb < 3)
        {
          ;
        }
        Monitor.Exit(mylock);
    
    
        //after
        L(o);
      }
      static void L(object oo)
      {
        int temp3 = (int)oo;
    
        switch (temp3)
        {
          case 1:
            M(oo);
            break;
          case 2:
            N(oo);
            break;
          case 4:
            O(oo);
            break;
          default:
            Debug.Assert(false, "fool3");
            break;
        }
      }
      static void M(object o)
      {
        // breaks here at the same time as N and Q
        Interlocked.Increment(ref cc);
        while (cc < 3)
        {
          ;
        }
        //BP3 - 1 in M, 2 in N, 3 still in J, 4 in O, 5 in Q
        Debugger.Break();
        Interlocked.Increment(ref cc);
        while (true)
          Thread.Sleep(500); // for ever
      }
      static void N(object o)
      {
        // breaks here at the same time as M and Q
        Interlocked.Increment(ref cc);
        while (cc < 4)
        {
          ;
        }
        R(o);
      }
      static void O(object o)
      {
        Task t5 = Task.Factory.StartNew(P, TaskCreationOptions.AttachedToParent);
        t5.Wait();
        R(o);
      }
      static void P()
      {
        Console.WriteLine("t5 runs " + Task.CurrentId.ToString());
        Q();
      }
      static void Q()
      {
        // breaks here at the same time as N and M
        Interlocked.Increment(ref cc);
        while (cc < 4)
        {
          ;
        }
        // task 5 dies here freeing task 4 (its parent)
        Console.WriteLine("t5 dies " + Task.CurrentId.ToString());
        waitFor5 = false;
      }
      static void R(object o)
      {
        if ((int)o == 2)
        {
          //wait for task5 to die
          while (waitFor5) { ;}
    
    
          int i;
          //spin up all procs
          for (i = 0; i < pcount - 4; i++)
          {
            Task t = Task.Factory.StartNew(() => { while (true);});
            Console.WriteLine("Started task " + t.Id.ToString());
          }
    
          Task.Factory.StartNew(T, i + 1 + 5, TaskCreationOptions.AttachedToParent); //scheduled
          Task.Factory.StartNew(T, i + 2 + 5, TaskCreationOptions.AttachedToParent); //scheduled
          Task.Factory.StartNew(T, i + 3 + 5, TaskCreationOptions.AttachedToParent); //scheduled
          Task.Factory.StartNew(T, i + 4 + 5, TaskCreationOptions.AttachedToParent); //scheduled
          Task.Factory.StartNew(T, (i + 5 + 5).ToString(), TaskCreationOptions.AttachedToParent); //scheduled
    
          //BP4 - 1 in M, 2 in R, 3 in J, 4 in R, 5 died
          Debugger.Break();
        }
        else
        {
          Debug.Assert((int)o == 4);
          t3.Wait();
        }
      }
      static void T(object o)
      {
        Console.WriteLine("Scheduled run " + Task.CurrentId.ToString());
      }
      static Task t1, t2, t3, t4;
      static int aa = 0;
      static int bb = 0;
      static int cc = 0;
      static bool waitFor1 = true;
      static bool waitFor5 = true;
      static int pcount;
      static S mylock = new S();
    }
    

Nachdem Sie die Codedatei aktualisiert haben, speichern Sie Die Änderungen, und erstellen Sie die Lösung.

  1. Wählen Sie im Menü "Datei " die Option "Alle speichern" aus.

  2. Wählen Sie im Menü Erstellen die Option Lösung neu erstellen aus.

Beachten Sie, dass es vier Aufrufe gibt Debugger.Break (DebugBreak im C++-Beispiel). Daher müssen Sie keine Haltepunkte einfügen. Wenn Sie die Anwendung gerade ausführen, wird sie im Debugger bis zu vier Mal abgebrochen.

"Verwenden Sie die Ansicht im Fenster 'Parallele Stapel: Threads'"

Wählen Sie zunächst im Menü " Debuggen " die Option "Debuggen starten" aus. Warten Sie, bis der erste Haltepunkt erreicht ist.

Anzeigen des Aufrufstapels eines einzelnen Threads

  1. Zeigen Sie im Menü "Debuggen" auf "Windows" und wählen Sie dann "Threads" aus. Docken Sie das Threads-Fenster am unteren Rand von Visual Studio an.

  2. Zeigen Sie im Menü Debuggen auf Windows und wählen Sie dann Aufrufliste aus. Andocken Sie das Fenster "Anrufstapel " am unteren Rand von Visual Studio.

  3. Doppelklicken Sie im Threads-Fenster auf einen Thread, um ihn aktuell zu machen. Aktuelle Threads weisen einen gelben Pfeil auf. Wenn Sie den aktuellen Thread ändern, wird dessen Aufrufstapel im Fenster "Anrufstapel " angezeigt.

Untersuchen Sie das Fenster "Parallele Stapel"

Zeigen Sie im Menü "Debuggen " auf Windows , und wählen Sie dann "Parallele Stapel" aus. Stellen Sie sicher, dass Threads im Feld in der oberen linken Ecke ausgewählt sind.

Mithilfe des Fensters "Parallele Stapel" können Sie mehrere Aufrufstapel gleichzeitig in einer Ansicht anzeigen. Die folgende Abbildung zeigt das Fenster "Parallele Stapel" oberhalb des Fensters "Aufrufstapel ".

Screenshot der Ansicht

Thread-Ansicht im Fenster

Der Aufrufstapel des Hauptthreads wird in einem Feld angezeigt, und die Aufrufstapel für die anderen vier Threads werden in einem anderen Feld gruppiert. Vier Threads werden gruppiert, da ihre Stapelframes dieselben Methodenkontexte aufweisen; das heißt, sie befinden sich in den gleichen Methoden: A, , Bund C. Um die Thread-IDs und Namen der Threads anzuzeigen, die dasselbe Feld gemeinsam verwenden, zeigen Sie mit der Maus auf das Feld mit der Kopfzeile ([#] Threads). Der aktuelle Thread wird fett formatiert angezeigt.

Screenshot des Tooltips mit Thread-IDs und Namen.

Tooltip, der Thread-IDs und Namen anzeigt

Der gelbe Pfeil gibt den aktiven Stapelrahmen des aktuellen Threads an.

Sie können festlegen, wie viele Details für die Stapelframes (Modulnamen, Parametertypen, Parameternamen, Parameterwerte, Zeilennummern und Byte-Offsets) angezeigt werden sollen, indem Sie im Fenster "Aufrufstapel " mit der rechten Maustaste klicken.

Eine blaue Hervorhebung um ein Feld zeigt an, dass der aktuelle Thread Teil dieses Felds ist. Der aktuelle Thread wird auch durch den fett formatierten Stackframe im Tooltip angegeben. Wenn Sie im Threads-Fenster auf den Hauptthread doppelklicken, können Sie beobachten, dass der Hervorhebungspfeil im Fenster "Parallele Stapel" entsprechend verschoben wird.

Screenshot des hervorgehobenen Hauptthreads im Fenster

Hervorgehobener Hauptthread im Fenster

Fortsetzen der Ausführung bis zum zweiten Haltepunkt

Um die Ausführung fortzusetzen, bis der zweite Haltepunkt erreicht ist, wählen Sie im Menü "Debuggen" die Option "Weiter" aus. Die folgende Abbildung zeigt die Threadbaumstruktur am zweiten Haltepunkt.

Screenshot des Fensters

Fenster

Am ersten Haltepunkt gingen alle vier Threads von der Methode S.A zur Methode S.B und anschließend zur Methode S.C. Diese Informationen sind weiterhin im Fenster "Parallele Stapel" sichtbar, aber die vier Threads sind weiter vorangekommen. Einer von ihnen fuhr nach S.D und dann S.E. Eine weitere weiter nach S.F, S.G und S.H. Zwei andere fuhren nach S.I und S.J, und von dort ging einer von ihnen nach S.K und die andere weiter zu Nichtbenutzer-externem Code.

Sie können mit dem Mauszeiger auf Stapelframes zeigen, um Thread-IDs sowie weitere Framedetails anzuzeigen. Die blaue Hervorhebung gibt den aktuellen Thread an, und der gelbe Pfeil gibt den aktiven Stapelrahmen des aktuellen Threads an.

Sie können mit dem Mauszeiger auf die Feldkopfzeile zeigen, z. B. 1 Thread oder 2 Threads, um die Thread-IDs der Threads anzuzeigen. Sie können mit dem Mauszeiger auf Stapelframes zeigen, um Thread-IDs sowie weitere Framedetails anzuzeigen. Die blaue Hervorhebung gibt den aktuellen Thread an, und der gelbe Pfeil gibt den aktiven Stapelrahmen des aktuellen Threads an.

Das Symbol für "Gewebefäden" (verflochtene Linien) zeigt die aktiven Stapelrahmen der nicht aktuellen Threads an. Doppelklicken Sie im Fenster "Anrufstapel " auf S.B, um Frames zu wechseln. Das Fenster "Parallele Stapel" gibt den aktuellen Stapelrahmen des aktuellen Threads mithilfe eines gekrümmten Pfeilsymbols an.

Hinweis

Eine Beschreibung aller Symbole im Fenster "Parallele Stapel" finden Sie unter Verwenden des Fensters "Parallele Stapel".

Wechseln Sie im Fenster "Threads " zwischen Threads, und beobachten Sie, dass die Ansicht im Fenster "Parallele Stapel" aktualisiert wird.

Sie können zu einem anderen Thread oder zu einem anderen Frame eines anderen Threads wechseln, indem Sie das Kontextmenü im Fenster "Parallele Stapel" verwenden. Klicken Sie z. B. mit der rechten Maustaste auf S.J, zeigen Sie auf "Zu Frame wechseln", und wählen Sie dann einen Befehl aus.

Screenshot des Parallelstapel-Ausführungspfads.

Paralleler Stapelpfad der Ausführung

Klicken Sie mit der rechten Maustaste auf S.C und wählen Sie "Zu Frame wechseln" aus. Einer der Befehle weist ein Häkchen auf, das den Stapelrahmen des aktuellen Threads angibt. Sie können zu diesem Rahmen desselben Threads wechseln (nur der gekrümmte Pfeil bewegt), oder Sie können zum anderen Thread wechseln (die blaue Hervorhebung wird ebenfalls verschoben). Die folgende Abbildung zeigt das Untermenü.

Screenshot des Menüs

Stack-Menü mit 2 Optionen auf C, während J aktuell ist

Wenn ein Methodenkontext nur einem Stapelrahmen zugeordnet ist, zeigt die Feldkopfzeile 1 Thread an, und Sie können durch Doppelklicken darauf wechseln. Wenn Sie auf einen Methodenkontext doppelklicken, dem mehr als 1 Frame zugeordnet ist, wird das Menü automatisch angezeigt. Wenn Sie mit dem Mauszeiger auf die Methodenkontexte zeigen, beachten Sie das schwarze Dreieck rechts. Beim Anklicken dieses Dreiecks wird auch das Kontextmenü angezeigt.

Bei großen Anwendungen mit vielen Threads sollten Sie sich möglicherweise nur auf eine Teilmenge von Threads konzentrieren. Das Fenster "Parallele Stapel" kann Aufrufstapel nur für gekennzeichnete Threads anzeigen. Verwenden Sie zum Kennzeichnen von Threads das Kontextmenü oder die erste Zelle eines Threads.

Wählen Sie auf der Symbolleiste die Schaltfläche " Nur gekennzeichnet anzeigen " neben dem Listenfeld aus.

Screenshot des Fensters

Fenster für parallele Stapel und Tooltips

Jetzt werden nur gekennzeichnete Threads im Fenster "Parallele Stapel" angezeigt.

Ausführung fortsetzen bis zum dritten Haltepunkt

  1. Um die Ausführung fortzusetzen, bis der dritte Haltepunkt erreicht ist, wählen Sie im Menü "Debuggen " die Option "Weiter" aus.

    Wenn sich mehrere Threads in derselben Methode befinden, die Methode aber nicht am Anfang des Aufrufstapels lag, wird die Methode in verschiedenen Feldern angezeigt. Ein Beispiel für den aktuellen Unterbrechungspunkt ist S.L., das drei Stränge enthält und in drei Feldern angezeigt wird. Doppelklicken Sie auf S.L.

    Screenshot des Ausführungspfads im Parallel Stacks-Fenster.

    Ausführungspfad im Parallel Stacks-Fenster

    Beachten Sie, dass S.L in den anderen beiden Feldern fett formatiert ist, damit Sie sehen können, wo sie sonst angezeigt wird. Wenn Sie sehen möchten, welche Rahmen in S.L aufgerufen werden und welche Rahmen von S.L aufgerufen werden, wählen Sie auf der Symbolleiste die Schaltfläche "Ansicht auf Methoden umschalten" aus. Die folgende Abbildung zeigt die Methodenansicht des Fensters „Parallele Stapel“.

    Screenshot der Ansicht

    Methodenansicht im Fenster „Parallele Stapel“

    Beachten Sie, wie das Diagramm auf die ausgewählte Methode pivotiert und in einem eigenen Feld in der Mitte der Ansicht positioniert wurde. Die Angerufenen und Anrufer werden oben bzw. unten angezeigt. Wählen Sie die Schaltfläche " Methodenansicht umschalten " erneut aus, um diesen Modus zu verlassen.

    Das Kontextmenü des Fensters "Parallele Stapel" enthält auch die folgenden anderen Elemente.

    • Hexadezimalanzeige schaltet die Zahlen in den Tooltips zwischen dezimal und hexadezimal um.

    • Symboleinstellungen öffnen die entsprechenden Dialogfelder.

    • Anzeigen von Threads in Der Quelle schaltet die Anzeige von Threadmarkierungen in Ihrem Quellcode um, wodurch die Position von Threads im Quellcode angezeigt wird.

    • "Externer Code anzeigen" zeigt alle Frames an, auch wenn sie sich nicht im Benutzercode befinden. Versuchen Sie es, um zu sehen, wie sich das Diagramm erweitert, um die anderen Frames aufzunehmen (die möglicherweise abgeblendet sind, weil Sie dafür keine Symbole haben).

  2. Stellen Sie im Fenster "Parallele Stapel" sicher, dass sich die Schaltfläche " Automatischer Bildlauf zum aktuellen Stapelrahmen " auf der Symbolleiste befindet.

    Wenn Sie über große Diagramme verfügen und zum nächsten Haltepunkt wechseln, möchten Sie möglicherweise, dass die Ansicht automatisch zum aktiven Stapelframe des aktuellen Threads scrollen soll. d. h. der Thread, der zuerst auf den Haltepunkt trifft.

  3. Bevor Sie fortfahren, scrollen Sie im Fenster "Parallele Stapel" ganz nach links und nach unten.

Fortsetzen der Ausführung bis zum vierten Haltepunkt

  1. Um die Ausführung fortzusetzen, bis der vierte Haltepunkt erreicht ist, wählen Sie im Menü "Debuggen " die Option "Weiter" aus.

    Beachten Sie, wie die Ansicht automatisch in die Position eingerollt wurde. Wechseln Sie zwischen Threads im Threads-Fenster oder wechseln Sie zwischen Stack-Frames im Aufrufstapel-Fenster und beachten Sie, wie die Ansicht immer automatisch zu den richtigen Frames scrollt. Deaktivieren Sie die Option Automatischer Bildlauf zum aktuellen Werkzeugrahmen und zeigen Sie den Unterschied an.

    Die Vogelperspektive hilft auch bei großen Diagrammen im Fenster "Parallele Stapel" . Standardmäßig ist die Vogelperspektive aktiviert. Sie können die Einstellung jedoch umschalten, indem Sie auf die Schaltfläche zwischen den Bildlaufleisten in der unteren rechten Ecke des Fensters klicken, wie in der folgenden Abbildung dargestellt.

    Screenshot der Ansicht

    Vogelperspektive im Parallel Stacks-Fenster

    In der Vogelperspektive können Sie das Rechteck verschieben, um schnell durch das Diagramm zu navigieren.

    Eine weitere Möglichkeit zum Verschieben des Diagramms in eine beliebige Richtung besteht darin, einen leeren Bereich des Diagramms auszuwählen und an die gewünschte Stelle zu ziehen.

    Wenn Sie das Diagramm vergrößern und verkleineren möchten, halten Sie STRG gedrückt, während Sie das Mausrad bewegen. Wählen Sie alternativ die Zoomschaltfläche auf der Symbolleiste aus, und verwenden Sie dann das Zoomtool.

    Sie können die Stapel auch in einer top-down-Richtung anstelle von unten anzeigen, indem Sie auf das Menü "Extras " klicken, auf "Optionen" klicken und dann die Option unter dem Knoten "Debuggen " auswählen oder deaktivieren.

  2. Bevor Sie fortfahren, wählen Sie im Menü " Debuggen " die Option " Debuggen beenden " aus, um die Ausführung zu beenden.

Verwenden Sie das Fenster "Parallele Vorgänge" und die "Vorgangsansicht" des Fensters "Parallele Stapel"

Es wird empfohlen, die früheren Verfahren abzuschließen, bevor Sie fortfahren.

Starten Sie die Anwendung neu, bis der erste Haltepunkt erreicht ist:

  1. Wählen Sie im Menü " Debuggen " die Option "Debuggen starten " aus, und warten Sie, bis der erste Haltepunkt erreicht wurde.

  2. Zeigen Sie im Menü "Debuggen" auf "Windows" und wählen Sie dann "Threads" aus. Docken Sie das Threads-Fenster am unteren Rand von Visual Studio an.

  3. Zeigen Sie im Menü "Debuggen" auf Windows, und wählen Sie "Aufrufstapel" aus. Docken Sie das Fenster "Anrufstapel " am unteren Rand von Visual Studio an.

  4. Doppelklicken Sie im Threads-Fenster auf einen Thread, um ihn aktuell zu machen. Aktuelle Threads weisen den gelben Pfeil auf. Wenn Sie den aktuellen Thread ändern, werden die anderen Fenster aktualisiert. Als Nächstes untersuchen wir Aufgaben.

  5. Zeigen Sie im Menü " Debuggen " auf Windows, und wählen Sie dann "Aufgaben" aus. Die folgende Abbildung zeigt das Fenster "Aufgaben ".

    Screenshot von vier ausgeführten Aufgaben im Aufgabenfenster.

    Vier ausgeführte Aufgaben im Aufgabenfenster

    Für jede laufende Aufgabe können Sie die ID ablesen, die von der gleichnamigen Eigenschaft zurückgegeben wird, sowie die ID und den Namen des Threads, der sie ausführt, und deren Position. Bewegen Sie den Mauszeiger darüber, um eine QuickInfo mit dem gesamten Aufrufstapel anzuzeigen. Außerdem können Sie in der Spalte " Aufgabe " die Methode sehen, die an den Vorgang übergeben wurde. Mit anderen Worten, der Ausgangspunkt.

    Sie können eine beliebige Spalte sortieren. Beachten Sie die Sortierglyphe, die die Sortierspalte und -richtung angibt. Sie können die Spalten auch neu anordnen, indem Sie sie nach links oder rechts ziehen.

    Der gelbe Pfeil gibt den aktuellen Vorgang an. Sie können Aufgaben wechseln, indem Sie auf eine Aufgabe doppelklicken oder das Kontextmenü verwenden. Wenn Sie Aufgaben wechseln, wird der zugrunde liegende Thread aktuell, und die anderen Fenster werden aktualisiert.

    Wenn Sie manuell von einer Aufgabe zu einer anderen wechseln, gibt die Pfeilgliederung den aktuellen Debuggerkontext für eine nicht aktuelle Aufgabe an.

    Wenn Sie manuell von einer Aufgabe zu einer anderen wechseln, wird der gelbe Pfeil verschoben, aber ein weißer Pfeil zeigt weiterhin die Aufgabe an, die dazu führte, dass der Debugger abgebrochen wurde.

Fortsetzen der Ausführung bis zum zweiten Haltepunkt

Um die Ausführung fortzusetzen, bis der zweite Haltepunkt erreicht ist, wählen Sie im Menü "Debuggen" die Option "Weiter" aus.

Zuvor hat die Spalte "Status " alle Vorgänge als "Aktiv" angezeigt, aber jetzt sind zwei der Aufgaben blockiert. Aufgaben können aus vielen verschiedenen Gründen blockiert werden. Zeigen Sie in der Spalte "Status " auf eine Warteaufgabe, um zu erfahren, warum sie blockiert ist. In der folgenden Abbildung wartet beispielsweise Aufgabe 11 auf Aufgabe 12.

Screenshot von zwei wartenden Aufgaben im Aufgabenfenster.

Zuvor hat die Spalte "Status " alle Vorgänge als "Aktiv" angezeigt, aber jetzt sind zwei der Aufgaben blockiert. Aufgaben können aus vielen verschiedenen Gründen blockiert werden. Zeigen Sie in der Spalte "Status " auf eine Warteaufgabe, um zu erfahren, warum sie blockiert ist. In der folgenden Abbildung wartet beispielsweise Aufgabe 4 auf Aufgabe 5.

Zwei wartende Aufgaben im Aufgabenfenster

Aufgabe 4 wartet wiederum auf einem Monitor, der dem Thread gehört, der Aufgabe 2 zugewiesen ist. (Klicken Sie mit der rechten Maustaste auf die Kopfzeile, und wählen Sie "Spalten"> aus.Threadzuweisung zum Anzeigen des Threadzuweisungswerts für Aufgabe 2).

Wartende Aufgaben und QuickInfo im Fenster

Sie können eine Aufgabe kennzeichnen, indem Sie in der ersten Spalte des Fensters "Aufgaben " auf die Kennzeichnung klicken.

Sie können die Kennzeichnung verwenden, um Aufgaben zwischen verschiedenen Haltepunkten in derselben Debugsitzung nachzuverfolgen oder nach Aufgaben zu filtern, deren Aufrufstapel im Fenster "Parallele Stapel" angezeigt werden.

Wenn Sie zuvor das Fenster "Parallele Stapel" verwendet haben, haben Sie die Anwendungsthreads angezeigt. Zeigen Sie das Fenster "Parallele Stapel" erneut an, aber dieses Mal zeigen Sie die Anwendungsaufgaben an. Wählen Sie dazu "Aufgaben" im Feld oben links aus. Die folgende Abbildung zeigt die Aufgabenansicht.

Screenshot der Ansicht

Aufgabenansicht im Fenster

Threads, die derzeit keine Aufgaben ausführen, werden nicht in der Aufgabenansicht des Fensters "Parallele Stapel" angezeigt. Außerdem werden für Threads, die Aufgaben ausführen, einige der Stapelframes, die für Aufgaben nicht relevant sind, vom oberen und unteren Rand des Stapels gefiltert.

Zeigen Sie das Fenster "Aufgaben " erneut an. Klicken Sie mit der rechten Maustaste auf eine beliebige Spaltenüberschrift, um ein Kontextmenü für die Spalte anzuzeigen.

Sie können das Kontextmenü verwenden, um Spalten hinzuzufügen oder zu entfernen. Die Spalte "AppDomain" ist beispielsweise nicht ausgewählt. daher wird sie nicht in der Liste angezeigt. Wählen Sie "Übergeordnetes Element" aus. Die übergeordnete Spalte erscheint ohne Werte für keinen der vier Aufgaben.

Ausführung fortsetzen bis zum dritten Haltepunkt

Um die Ausführung fortzusetzen, bis der dritte Haltepunkt erreicht ist, wählen Sie im Menü "Debuggen " die Option "Weiter" aus.

Screenshot der Eltern-Kind-Ansicht im Fenster

Beachten Sie in diesem Beispiel, dass Aufgabe 11 und Aufgabe 12 im selben Thread ausgeführt werden (die Spalte "Threadzuweisung " anzeigen, wenn sie ausgeblendet ist). Diese Informationen werden nicht im Threads-Fenster angezeigt. Hier sehen Sie einen weiteren Vorteil des Fensters "Aufgaben ". Um dies zu bestätigen, zeigen Sie das Fenster "Parallele Stapel" an. Stellen Sie sicher, dass Sie Aufgaben anzeigen. Sie können Aufgaben 11 und 12 lokalisieren, indem Sie die Tooltips im Fenster Parallel Stacks anzeigen.

Vorgangsansicht im Fenster

Eine neue Aufgabe, Aufgabe 5, wird jetzt ausgeführt, und Aufgabe 4 wartet jetzt. Sie können sehen, warum, indem Sie mit dem Mauszeiger auf die Warteaufgabe im Statusfenster zeigen. Beachten Sie in der Spalte "Übergeordnetes Element", dass Aufgabe 4 das übergeordnete Element von Aufgabe 5 ist.

Um die Eltern-Kind-Beziehung besser zu visualisieren, klicken Sie mit der rechten Maustaste auf die Spaltenüberschriftszeile und wählen Sie dann die Eltern-Kind-Ansicht aus. Sie sollten die folgende Abbildung sehen.

Eltern-Kind-Ansicht im Aufgabenfenster

Beachten Sie, dass Aufgabe 4 und Aufgabe 5 im selben Thread ausgeführt werden (Die Spalte " Threadzuweisung " anzeigen, wenn sie ausgeblendet ist). Diese Informationen werden nicht im Threads-Fenster angezeigt. Hier sehen Sie einen weiteren Vorteil des Fensters "Aufgaben ". Um dies zu bestätigen, zeigen Sie das Fenster "Parallele Stapel" an. Stellen Sie sicher, dass Sie Aufgaben anzeigen. Suchen Sie Vorgänge 4 und 5, indem Sie im Fenster "Aufgaben " auf sie doppelklicken. Wenn Sie dies tun, wird die blaue Hervorhebung im Fenster "Parallele Stapel" aktualisiert. Sie können auch die Aufgaben 4 und 5 lokalisieren, indem Sie die QuickInfos im Fenster "Parallele Stapel" scannen.

Vorgangsansicht im Fenster

Klicken Sie im Fenster "Parallele Stapel" mit der rechten Maustaste auf S.P, und wählen Sie dann "Gehe zu Thread" aus. Das Fenster wechselt zur Thread-Ansicht, und der entsprechende Frame wird angezeigt. Sie können beide Aufgaben im selben Thread sehen.

Hervorgehobener Thread in der Threadsansicht

Dies ist ein weiterer Vorteil der Vorgangsansicht im Fenster "Parallele Stapel" im Vergleich zum Fenster "Threads ".

Fortsetzen der Ausführung bis zum vierten Haltepunkt

Um die Ausführung fortzusetzen, bis der dritte Haltepunkt erreicht ist, wählen Sie im Menü "Debuggen " die Option "Weiter" aus. Wählen Sie die ID-Spaltenüberschrift aus, um nach ID zu sortieren. Sie sollten die folgende Abbildung sehen.

Screenshot von vier Vorgangszuständen im Parallel Stacks-Fenster.

Aufgabe 10 und Vorgang 11 warten nun aufeinander und werden blockiert. Es gibt auch mehrere neue Vorgänge, die jetzt geplant sind. Geplante Aufgaben sind Aufgaben, die im Code gestartet wurden, aber noch nicht ausgeführt wurden. Daher zeigen die Spalten "Standort" und "Threadzuweisung " Standardmeldungen an oder sind leer.

Vier Vorgangszustände im Parallel Stacks-Fenster

Da Die Aufgabe 5 abgeschlossen ist, wird sie nicht mehr angezeigt. Wenn dies nicht auf Ihrem Computer der Fall ist und der Deadlock nicht angezeigt wird, gehen Sie einen Schritt weiter, indem Sie F11 drücken.

Aufgabe 3 und Aufgabe 4 warten nun aufeinander und werden blockiert. Es gibt auch fünf neue Vorgänge, die untergeordnete Elemente von Vorgang 2 sind und jetzt geplant sind. Geplante Aufgaben sind Aufgaben, die im Code gestartet wurden, aber noch nicht ausgeführt wurden. Daher sind die Spalten "Standort" und "Threadzuweisung " leer.

Zeigen Sie das Fenster "Parallele Stapel" erneut an. Die Überschrift jeder Box enthält eine QuickInfo, die die Thread-IDs und Namen anzeigt. Wechseln zur Aufgabenansicht im Fenster "Parallele Stapel" . Zeigen Sie mit der Maus auf einen Header, um die Vorgangs-ID und den Namen und den Status des Vorgangs anzuzeigen, wie in der folgenden Abbildung dargestellt.

Tooltipp für Kopfzeile im Fenster

Sie können die Aufgaben nach Spalte gruppieren. Klicken Sie im Fenster "Aufgaben " mit der rechten Maustaste auf die Spaltenüberschrift "Status ", und wählen Sie dann " Nach Status gruppieren" aus. Die folgende Abbildung zeigt das Fenster "Aufgaben " nach Status gruppiert.

Screenshot der gruppierten Aufgaben im Fenster

Gruppierte Aufgaben im Fenster

Sie können auch nach jeder anderen Spalte gruppieren. Durch Gruppieren von Aufgaben können Sie sich auf eine Teilmenge von Aufgaben konzentrieren. Jede aufklappbare Gruppe weist die Anzahl der Elemente auf, die gruppiert sind.

Das letzte Zu untersuchende Feature des Fensters "Aufgaben " ist das Kontextmenü, das angezeigt wird, wenn Sie mit der rechten Maustaste auf eine Aufgabe klicken.

Im Kontextmenü werden je nach Status der Aufgabe unterschiedliche Befehle angezeigt. Die Befehle könnten Folgendes umfassen: „Kopieren“, „Alle auswählen“, „Hexadezimalanzeige“, „Zu Aufgabe wechseln“, „Zugewiesenen Thread fixieren“, „Alle Threads außer diesem fixieren“, „Zugewiesenen Thread freigeben“ sowie „Flag“.

Sie können den zugrunde liegenden Thread einer Aufgabe oder Aufgaben fixieren, oder Sie können alle Threads außer dem zugewiesenen fixieren. Ein fixierter Thread wird im Fenster "Aufgaben " wie im Fenster "Threads " durch ein blaues Pausensymbol dargestellt.

Zusammenfassung

In dieser exemplarischen Vorgehensweise wurden die Debuggerfenster Parallele Aufgaben und Parallel Stacks veranschaulicht. Verwenden Sie diese Fenster für echte Projekte, die Multithread-Code verwenden. Sie können parallelen Code untersuchen, der in C++, C# oder Visual Basic geschrieben wurde.