Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez az oktatóanyag bemutatja, hogyan használhatja a Szálak nézetet a Párhuzamos Veremablakok ablakokban egy többszálú alkalmazás hibakereséséhez. Ez az ablak segít megérteni és ellenőrizni a többszálú kód futásidejű viselkedését.
A Szálak nézet C#, C++ és Visual Basic esetén támogatott. A C# és a C++ kódhoz mintakód tartozik, de a kódhivatkozások és illusztrációk némelyike csak a C# mintakódra vonatkozik.
A Szálak nézete segít Önnek a következőkben:
Több szál hívásveremvizualizációinak megtekintése, amely teljesebb képet nyújt az alkalmazás állapotáról, mint a Hívásverem ablak, amely csak az aktuális szál hívásveremét jeleníti meg.
Segítség az olyan problémák azonosításához, mint a blokkolt vagy holtpontú szálak.
Többszálú hívásverem
A hívásverem azonos szakaszai csoportosítva vannak az összetett alkalmazások vizualizációjának egyszerűsítése érdekében.
Az alábbi fogalmi animáció bemutatja, hogyan alkalmazza a rendszer a csoportosítást a hívásveremekre. Csak a hívásverem azonos szegmensei vannak csoportosítva. Vigye az egérmutatót egy csoportosított hívásverem fölé, hogy idenitfy a szálakat.
Mintakód áttekintése (C#, C++)
Az útmutató mintakódja egy olyan alkalmazáshoz készült, amely egy gorilla életének egy napját szimulálja. A gyakorlat célja annak megismerése, hogyan használható a Párhuzamos veremek ablak Szálnézete egy többszálú alkalmazás hibakereséséhez.
A példa egy holtpontra mutat, amely akkor fordul elő, ha két szál várakozik egymásra.
A hívásverem intuitívsá tétele érdekében a mintaalkalmazás a következő szekvenciális lépéseket hajtja végre:
- Létrehoz egy gorillát jelképező objektumot.
- Gorilla felébred.
- Gorilla megy egy reggeli sétára.
- Gorilla banánt talál a dzsungelben.
- Gorilla eszik.
- A gorilla bohóckodik.
A mintaprojekt létrehozása
A projekt létrehozása:
Nyissa meg a Visual Studiót, és hozzon létre egy új projektet.
Ha a kezdőablak nincs megnyitva, válassza Fájl>Ablak indításalehetőséget.
A Start ablakban válassza az Új projekt lehetőséget.
Az Új projekt létrehozása ablakban írja be vagy írja be a keresőmezőbe a konzolt . Ezután válassza a C# vagy a C++ elemet a Nyelv listából, majd válassza a Windowst a Platform listából.
A nyelv- és platformszűrők alkalmazása után válassza ki a választott nyelv konzolalkalmazását , majd válassza a Tovább gombot.
Note
Ha nem látja a megfelelő sablont, lépjen az Eszközök>lekérése eszközök és szolgáltatások lapra, amely megnyitja a Visual Studio Installert. Válassza a .NET asztali fejlesztés munka terhelését, majd válassza a Módosítás lehetőséget.
Az új projekt konfigurálása ablakban írjon be egy nevet, vagy használja az alapértelmezett nevet a Projektnév mezőbe. Ezután válassza a Következőlehetőséget.
.NET-projekt esetén válassza az ajánlott cél keretrendszert vagy a .NET 8-at, majd válassza a Létrehozás lehetőséget.
Megjelenik egy új konzolprojekt. A projekt létrehozása után megjelenik egy forrásfájl.
Nyissa meg a .cs (vagy .cpp) kódfájlt a projektben. Üres kódfájl létrehozásához törölje annak tartalmát.
Illessze be a választott nyelvhez tartozó alábbi kódot az üres kódfájlba.
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"); } } }A Fájl menüben válassza az Összes mentése lehetőséget.
A Build menüben válassza a Megoldás összeállításalehetőséget.
A Párhuzamos verem ablak Szálak nézetének használata
A hibakeresés megkezdéséhez:
A Hibakeresés menüben válassza a Hibakeresés indítása (vagy F5) lehetőséget, és várja meg az első
Debugger.Break()találatot.Note
A C++-ban a hibakereső szünetel
__debug_break()helyen. A cikkben szereplő további kódhivatkozások és illusztrációk a C#-verzióra vonatkoznak, de ugyanezek a hibakeresési alapelvek érvényesek a C++-ra is.Nyomja le egyszer az F5 billentyűt, és a hibakereső ismét megáll ugyanazon
Debugger.Break()a sorban.Ez szünetel a második hívásban
Gorilla_Start, amely egy második szálon belül történik.Tip
A hibakereső szálonként törik át a kódot. Ez azt jelenti például, hogy ha az F5 billentyűt lenyomva folytatja a végrehajtást, és az alkalmazás eléri a következő töréspontot, az egy másik szálon lévő kódra törhet. Ha hibakeresési célból kell kezelnie ezt a viselkedést, hozzáadhat további töréspontokat, feltételes töréspontokat, vagy használhatja az Összes megszakítást. További információ a feltételes töréspontok használatáról: Egyetlen szál követése feltételes töréspontokkal.
A Párhuzamos halmok ablak megnyitásához válassza a Hibakeresés > Windows > Párhuzamos Halmok lehetőséget, majd az ablakban a Nézet legördülő listából válassza a Szálak lehetőséget.
A Szálak nézetben az aktuális szál veremkerete és hívási útvonala kék színnel van kiemelve. A szál aktuális helyét a sárga nyíl mutatja.
Figyelje meg, hogy a hívásverem
Gorilla_Startcímkéje 2 szál. Amikor legutóbb lenyomta az F5 billentyűt, elindított egy másik szálat. Az összetett alkalmazások egyszerűsítése érdekében az azonos hívásveremek egyetlen vizuális ábrázolásba vannak csoportosítva. Ez leegyszerűsíti a potenciálisan összetett információkat, különösen a sok szálat tartalmazó forgatókönyvekben.A hibakeresés során beállíthatja, hogy megjelenjen-e külső kód. A funkció váltásához válassza a Külső kód megjelenítése lehetőséget, vagy törölje a jelölését. Ha külső kódot jelenít meg, akkor is használhatja ezt az útmutatót, de az eredmények eltérhetnek az ábráktól.
Nyomja le ismét az F5 billentyűt, és a hibakereső a
Debugger.Break()sorban aMorningWalkmetódusnál szünetel.A Párhuzamos veremek ablak az aktuális végrehajtási szál helyét jeleníti meg a
MorningWalkmetódusban.
Vigye az egérmutatót a
MorningWalkmetódus fölé, hogy megkapja a kapcsolt hívásverem által képviselt két szálról szóló információkat.Az aktuális szál a Hibakeresés eszköztár Szál listájában is megjelenik.
A szál lista használatával a hibakereső környezetet egy másik szálra válthatja. Ez nem módosítja az aktuális végrehajtási szálat, csak a hibakereső környezetet.
Másik lehetőségként a hibakereső környezetét úgy is módosíthatja, hogy duplán kattint egy metódusra a Szálak nézetben, vagy kattintson a jobb gombbal egy metódusra a Szálak nézetben, és válassza a Váltás keretre>[szálazonosító] lehetőséget.
Nyomja le ismét az F5 billentyűt, ekkor a hibakereső megáll a második szál
MorningWalkmetódusánál.
A szál végrehajtásának időzítésétől függően ezen a ponton különálló vagy csoportosított hívásveremek jelennek meg.
Az előző ábrán a két szál hívásveremei részben vannak csoportosítva. A hívásveremek azonos szegmensei csoportosítva vannak, a nyílvonalak pedig az elválasztott (azaz nem azonos) szegmensekre mutatnak. Az aktuális veremkeretet a kék kiemelés jelzi.
Nyomja le ismét az F5 billentyűt, ekkor hosszú késleltetést fog tapasztalni, a Szálak nézet pedig nem jelenít meg hívásverem adatait.
A késést holtpont okozza. A Szálak nézetben semmi sem jelenik meg, mert bár a szálak blokkolódhatnak, a hibakereső jelenleg nincs szüneteltetve.
Note
C++-ban egy hibakeresési hiba is megjelenik, amely jelzi, hogy a
abort()hívás történt.Tip
Az Összes megszakítás gomb jó módszer a hívásverem információinak lekérésére, ha holtpont áll fenn, vagy az összes szál jelenleg le van tiltva.
A hibakeresési eszköztár IDE tetején válassza az Összes megszakítás gombot (szüneteltetés ikon), vagy használja a Ctrl+ Alt+ Break billentyűkombinációt.
A hívásverem felső része a Szálak nézetben azt mutatja, hogy
FindBananasholtponton van. A végrehajtási mutatóFindBananasegy görbült zöld nyíl, amely az aktuális hibakereső környezetet jelzi, de azt is jelzi, hogy a szálak jelenleg nem futnak.Note
C++-ban nem találhatók meg a hasznos "holtpont-észlelési" információk és ikonok. A görbült zöld nyíl
Jungle.FindBananasazonban továbbra is a holtpont helyére utal.A kódszerkesztőben megtaláljuk a görbületes zöld nyilat a
lockfüggvényben. A két szál blokkolva van alockfüggvényen aFindBananasmetódusban.A szálvégrehajtás sorrendjétől függően a holtpont megjelenik vagy a
lock(tree)vagy alock(banana_bunch)utasításban.A
lockhívás blokkolja a szálakat aFindBananasmetódusban. Az egyik szál arra vár, hogy a másik szál feloldja a zárolásttree, a másik szál azonban arra vár, hogy a zárolástbanana_bunchfeloldja, mielőtt feloldhatja a zárolásttree. Ez egy példa egy klasszikus holtpontra, amely akkor fordul elő, ha két szál várakozik egymásra.A Copilot használata esetén az AI által generált szálösszesítőket is lekérheti a lehetséges holtpontok azonosításához.
A mintakód javítása
A kód javításához mindig több zárolást alkalmazzon egy konzisztens, globális sorrendben minden szálon. Ez megakadályozza a körkörös várakozást, és kiküszöböli a holtpontokat.
A holtpont javításához cserélje le a kódot
MorningWalka következő kódra.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; }Indítsa újra az alkalmazást.
Summary
Ez az útmutató a Párhuzamos verem hibakereső ablakát mutatta be. Használja ezt az ablakot többszálú kódot használó valós projekteken. A C++, C# vagy Visual Basic nyelven írt párhuzamos kódokat megvizsgálhatja.