Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här självstudien visar hur du använder vyn Trådar i Parallella stackfönster för att felsöka ett flertrådat program. Det här fönstret hjälper dig att förstå och verifiera körningsbeteendet för multitrådad kod.
Trådvyn stöds för C#, C++ och Visual Basic. Exempelkoden tillhandahålls för C# och C++, men vissa av kodreferenserna och illustrationerna gäller endast för C#-exempelkoden.
Trådarvyn hjälper dig med att:
- Visa anropsstackens visualiseringar för flera trådar, vilket ger en mer fullständig bild av apptillståndet än fönstret Samtalsstack, som bara visar anropsstacken för den aktuella tråden. 
- Hjälp med att identifiera problem som blockerade eller låsta trådar. 
Multitrådade anropsstackar
Identiska delar av anropsstacken grupperas tillsammans för att förenkla visualiseringen för komplexa appar.
Följande konceptuella animering visar hur gruppering tillämpas på anropsstackar. Endast identiska segment i en anropsstack grupperas. Hovra över en grupperad anropsstack för att idenitfy trådarna.
               
              
            
Exempelkodöversikt (C#, C++)
Exempelkoden i den här genomgången är för ett program som simulerar en dag i en gorillas liv. Syftet med övningen är att förstå hur du använder vyn Trådar i fönstret Parallella staplar för att felsöka ett program med flera flöden.
Exemplet innehåller ett exempel på ett dödläge som inträffar när två trådar väntar på varandra.
För att göra anropsstacken intuitiv utför exempelappen följande sekventiella steg:
- Skapar ett objekt som representerar en gorilla.
- Gorilla vaknar.
- Gorillan går på en morgonpromenad.
- Gorilla hittar bananer i djungeln.
- Gorilla äter.
- Gorilla sysslar med rackartyg.
Skapa exempelprojektet
Så här skapar du projektet:
- Öppna Visual Studio och skapa ett nytt projekt. - Om startfönstret inte är öppet väljer du Fil>Startfönster. - I startfönstret väljer du Nytt projekt. - I fönstret Skapa ett nytt projekt anger eller skriver du konsolen i sökrutan. Välj sedan C# eller C++ i listan Språk och välj sedan Windows i listan Plattform. - När du har tillämpat språk- och plattformsfilter väljer du Konsolapp för ditt valda språk och väljer sedan Nästa. - Note - Om du inte ser rätt mall går du till Verktyg>Hämta verktyg och funktioner... som öppnar Installationsprogrammet för Visual Studio. Välj arbetsbelastningen för .NET-skrivbordsutveckling och välj då Ändra. - I fönstret Konfigurera det nya projektet skriver du ett namn eller använder standardnamnet i rutan Projektnamn . Välj sedan Nästa. - För ett .NET-projekt väljer du antingen det rekommenderade målramverket eller .NET 8 och väljer sedan Skapa. - Ett nytt konsolprojekt visas. När projektet har skapats visas en källfil. 
- Öppna kodfilen .cs (eller .cpp) i projektet. Ta bort innehållet för att skapa en tom kodfil. 
- Klistra in följande kod för det valda språket i den tomma kodfilen. - using System.Diagnostics; namespace Multithreaded_Deadlock { class Jungle { public static readonly object tree = new object(); public static readonly object banana_bunch = new object(); public static Barrier barrier = new Barrier(2); public static int FindBananas() { // Lock tree first, then banana lock (tree) { lock (banana_bunch) { Console.WriteLine("Got bananas."); return 0; } } } static void Gorilla_Start(object lockOrderObj) { Debugger.Break(); bool lockTreeFirst = (bool)lockOrderObj; Gorilla koko = new Gorilla(lockTreeFirst); int result = 0; var done = new ManualResetEventSlim(false); Thread t = new Thread(() => { result = koko.WakeUp(); done.Set(); }); t.Start(); done.Wait(); } static void Main(string[] args) { List<Thread> threads = new List<Thread>(); // Start two threads with opposite lock orders threads.Add(new Thread(Gorilla_Start)); threads[0].Start(true); // First gorilla locks tree then banana threads.Add(new Thread(Gorilla_Start)); threads[1].Start(false); // Second gorilla locks banana then tree foreach (var t in threads) { t.Join(); } } } class Gorilla { private readonly bool lockTreeFirst; public Gorilla(bool lockTreeFirst) { this.lockTreeFirst = lockTreeFirst; } public int WakeUp() { int myResult = MorningWalk(); return myResult; } public int MorningWalk() { Debugger.Break(); if (lockTreeFirst) { lock (Jungle.tree) { Jungle.barrier.SignalAndWait(5000); // For thread timing consistency in sample Jungle.FindBananas(); GobbleUpBananas(); } } else { lock (Jungle.banana_bunch) { Jungle.barrier.SignalAndWait(5000); // For thread timing consistency in sample Jungle.FindBananas(); GobbleUpBananas(); } } return 0; } public void GobbleUpBananas() { Console.WriteLine("Trying to gobble up food..."); DoSomeMonkeyBusiness(); } public void DoSomeMonkeyBusiness() { Thread.Sleep(1000); Console.WriteLine("Monkey business done"); } } }
- På menyn Arkiv väljer du Spara alla. 
- På menyn Build väljer du Build Solution. 
Använd vyn Trådar i fönstret Parallella staplar
Så här börjar du felsöka:
- På menyn Felsök väljer du Starta felsökning (eller F5) och väntar på att den första - Debugger.Break()ska slås.- Note - I C++pausar felsökningsprogrammet i - __debug_break(). Resten av kodreferenserna och illustrationerna i den här artikeln gäller för C#-versionen, men samma felsökningsprinciper gäller för C++.
- Tryck på F5 en gång så pausar felsökningsprogrammet igen på samma - Debugger.Break()rad.- Detta pausar i det andra anropet till - Gorilla_Start, som inträffar inom en separat tråd.- Tip - Felsökningsprogrammet bryter sig in i kod per tråd. Det innebär till exempel att om du trycker på F5 för att fortsätta körningen och appen når nästa brytpunkt kan den brytas in i kod i en annan tråd. Om du behöver hantera det här beteendet i felsökningssyfte kan du lägga till ytterligare brytpunkter, villkorsstyrda brytpunkter eller använda Bryt alla. Mer information om hur du använder villkorsstyrda brytpunkter finns i Följ en enda tråd med villkorsstyrda brytpunkter. 
- Välj Felsöka > Windows > Parallel Stacks för att öppna fönstret Parallella staplar och välj sedan Trådar i listrutan Visa i fönstret.   - I vyn Trådar markeras stackram och anropsväg för den aktuella tråden med blå färg. Trådens aktuella plats visas med den gula pilen. - Observera att etiketten för anropsstacken för - Gorilla_Startär 2 trådar. När du senast tryckte på F5 startade du en annan tråd. För förenkling i komplexa appar grupperas identiska anropsstackar i en enda visuell representation. Detta förenklar potentiellt komplex information, särskilt i scenarier med många trådar.- Under felsökningen kan du ändra om extern kod ska visas. Om du vill växla funktionen väljer eller avmarkerar du Visa extern kod. Om du visar extern kod kan du fortfarande använda den här genomgången, men dina resultat kan skilja sig från illustrationerna. 
- Tryck på F5 igen och felsökningsprogrammet pausar på - Debugger.Break()raden i- MorningWalk-metoden.- Fönstret Parallella staplar visar platsen för den aktuella exekverande tråden i - MorningWalk-metoden.  
- Hovra över - MorningWalkmetoden för att få information om de två trådar som representeras av den grupperade anropsstacken.- Den aktuella tråden visas också i listan Tråd i verktygsfältet Felsökning.   - Du kan använda trådlistan för att växla felsökningskontexten till en annan tråd. Detta ändrar inte den aktuella tråden, bara felsökarens kontext. - Du kan också växla felsökningskontexten genom att dubbelklicka på en metod i vyn Trådar eller genom att högerklicka på en metod i vyn Trådar och välja Växla till ram>[tråd-ID]. 
- Tryck på F5 igen så pausas felsökningsprogrammet i metoden för den andra tråden.   - Beroende på tidpunkten för trådkörningen kommer du vid den här tidpunkten att se antingen separata eller grupperade anropsstackar. - I föregående bild grupperas anropsstackarna för de två trådarna delvis. De identiska segmenten i anropsstacken grupperas och pillinjer pekar på segmenten som är avgränsade (det vill säga inte identiska). Den aktuella stackramen indikeras av den blå markeringen. 
- Tryck på F5 igen så visas en lång fördröjning och vyn Trådar visar ingen information om anropsstacken. - Fördröjningen orsakas av ett dödläge. Ingenting visas i vyn Trådar eftersom du inte för närvarande är pausad i felsökningsprogrammet, även om trådar kan blockeras. - Note - I C++ ser du också ett fel i felsökningsläge som anger att - abort()har anropats.- Tip - Knappen Bryt alla är ett bra sätt att få information om anropsstacken om ett dödläge inträffar eller om alla trådar för närvarande är blockerade. 
- Längst upp i IDE:t i verktygsfältet Felsökning väljer du knappen Bryt alla (pausikon) eller använder Ctrl + Alt + Break. - Överst i anropsstacken i Trådar-vyn visas att - FindBananasär i dödläge. Körningspekaren i- FindBananasär en krökt grön pil som anger den aktuella felsökningskontexten, men visar också att trådarna för närvarande inte körs.- Note - I C++, ser du inte den användbara "deadlock detected"-informationen och ikonerna. Men du hittar fortfarande den curlade gröna pilen i - Jungle.FindBananas, vilket antyder platsen för dödläget.- I kodredigeraren hittar vi den curlade gröna pilen - locki funktionen. De två trådarna blockeras på- lockfunktionen i- FindBananas-metoden.- Beroende på ordningen för trådkörningen uppstår deadlocken antingen i - lock(tree)- eller- lock(banana_bunch)-instruktionen.- Anropet till - lockblockerar trådarna i- FindBananasmetoden. En tråd väntar på att låset på- treeska släppas av den andra tråden, men den andra tråden väntar på att låset på- banana_bunchska släppas innan den kan släppa låset på- tree. Det här är ett exempel på ett klassiskt dödläge som inträffar när två trådar väntar på varandra.- Om du använder Copilot kan du också få AI-genererade trådsammanfattningar som hjälper dig att identifiera potentiella dödlägen. 
Åtgärda exempelkoden
Åtgärda den här koden genom att alltid hämta flera lås i en konsekvent, global ordning i alla trådar. Detta förhindrar cirkulära väntetider och eliminerar dödlägen.
- Åtgärda dödläget genom att ersätta koden i - MorningWalkmed följande kod.- public int MorningWalk() { Debugger.Break(); // Always lock tree first, then banana_bunch lock (Jungle.tree) { Jungle.barrier.SignalAndWait(5000); // OK to remove lock (Jungle.banana_bunch) { Jungle.FindBananas(); GobbleUpBananas(); } } return 0; }
- Starta om appen. 
Summary
Den här genomgången visade felsökningsfönstret Parallel Stacks . Använd det här fönstret i verkliga projekt som använder multitrådad kod. Du kan undersöka parallell kod som skrivits i C++, C#eller Visual Basic.
 
              
               
              
               
              
              