Denne artikel er en spejling af maskinoversættelse, klik venligst her for at springe til den oprindelige artikel.

Udsigt: 6277|Svar: 2

[Kommunikation] [Drej] En sætning Opgave. Resultatet bliver låst, hvordan skriver man ellers denne kode?

[Kopier link]
Opslået den 7-8-2022 kl. 21:11:58 | | | |
1: Baggrund

1. Fortæl historier

For et par dage siden, da jeg indekserede artiklen om .NET Advanced Debugging til github, fandt jeg en interessant kommentar, se artiklen for detaljer, skærmbilledet er som følger:



Det betyder sandsynligvis, at udførelsen af Task.Result under hovedtråden i Winform vil forårsage en deadlock, jeg kiggede også på referencelinket på billedet, Stephen er den absolutte chef, men denne artikel handler primært om indoktrinering af et stort afsnit tekst, og den lader dig ikke rigtig se det, du ser, så jeg vil analysere det fra windbgs perspektiv.

2: Vindbg-analyse

1. Vil det virkelig være fastlåst?

Selvfølgelig har jeg ikke spillet Winform i mange år, og jeg kan ikke finde ud af, om det vil, i hvert fald ikke på konsollen.

Koden er meget simpel, kør programmet, klik klik, og ganske rigtigt, brugerfladen sidder fast, hvilket er lidt utroligt.

2. Se efter årsagen til dødvandet

Dernæst, skynd dig at vedhæfte windbg til processen for at finde ud af det.

1) Se på hovedtråden
Brugerfladen reagerer ikke, så naturligvis sidder hovedtråden fast, så du skal kigge på, hvad hovedtråden laver lige nu. Brug kommandoen ~0s + !clrstack.

0:000> !clrstack
OS tråd-id: 0x5a10 (0)
        Child SP IP-opkaldssted
0000004d10dfde00 00007ffb889a10e4 [GCFrame: 0000004d10dfde00]
0000004d10dfdf28 00007ffb889a10e4 [HelperMethodFrame_1OBJ: 0000004d10dfdf28] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)
0000004d10dfe040 00007ffb66920d64 System.Threading.ManualResetEventSlim.Wait(Int32, System.Threading.CancellationToken)
0000004d10dfe0d0 00007ffb6691b4bb System.Threading.Tasks.SpinThenBlockingWait(Int32, System.Threading.CancellationToken)
0000004d10dfe140 00007ffb672601d1 System.Threading.Tasks.InternalWait(Int32, System.Threading.CancellationToken)
0000004d10dfe210 00007ffb6725cfa7 System.Threading.Tasks.Task'1[[System.__Canon, mscorlib]]. GetResultCore (boolesk)
0000004d10dfe250 00007ffb18172a1b WindowsFormsApp4.Form1.button1_Click(System.Object, System.EventArgs) [E:\net5\ConsoleApp1\WindowsFormsApp4\Form1.cs @ 26]
0000004d10dfe2b0 00007ffb3a024747 System.Windows.Forms.Control.OnClick(System.EventArgs)
0000004d10dfe2f0 00007ffb3a027b83 System.Windows.Forms.Button.OnClick(System.EventArgs)
0000004d10dfe340 00007ffb3a837231 System.Windows.Forms.Button.OnMouseUp(System.Windows.Forms.MouseEventArgs)
0000004d10dfe400 00007ffb3a7e097d System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message ByRef, System.Windows.Forms.MouseButtons, Int32)
0000004d10dfe480 00007ffb3a0311cc System.Windows.Forms.Control.WndProc(System.Windows.Forms.Besked ved reference)
0000004d10dfe540 00007ffb3a0b0c97 System.Windows.Forms.ButtonBase.WndProc(System.Windows.Forms.Besked ByRef)
0000004d10dfe5c0 00007ffb3a0b0be5 System.Windows.Forms.Button.WndProc(System.Windows.Forms.Message ByRef)
0000004d10dfe5f0 00007ffb3a030082 System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)
0000004d10dfe690 00007ffb3a765a02 DomainBoundILStubClass.IL_STUB_ReversePInvoke(Int64, Int32, Int64, Int64)
0000004d10dfe9d0 00007ffb776d221e [InlinedCallFrame: 0000004d10dfe9d0] System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
0000004d10dfe9d0 00007ffb3a0b9489 [InlinedCallFrame: 0000004d10dfe9d0] System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
0000004d10dfe9a0 00007ffb3a0b9489 DomainBoundILStubClass.IL_STUB_PInvoke(MSG ByRef)
0000004d10dfea60 00007ffb3a046661 System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop( IntPtr, Int32, Int32)
0000004d10dfeb50 00007ffb3a045fc7 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
0000004d10dfebf0 00007ffb3a045dc2 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
0000004d10dfec50 00007ffb181708e2 WindowsFormsApp4.Program.Main() [E:\net5\ConsoleApp1\WindowsFormsApp4\Program.cs @ 19]
0000004d10dfee78 00007ffb776d6923 [GCFrame: 0000004d10dfee78]
Ud fra stackens output sidder hovedtråden endelig fast på Monitor.ObjWait under Task.Result, hvilket betyder, at den endnu ikke har hentet den sidste jsonString, hvilket er meget mærkeligt, det er flere minutter siden, er der et problem med netværket? Mit net er 100 meter fyldt med ildkraft...

2) Hvor blev jsonString af?
Hvis jsonString findes på den administrerede heap, betyder det, at der er noget i programmet, der får resultatet til at forsinke, brug kommandoen !dumpheap -type String -min 8500 + !do 000001f19002fcf0 for at se, som vist i figuren nedenfor:



Ud fra figuren kan det tydeligt ses, at html er tilbage, og da det hele er tilbage, hvorfor er Task.Result så ikke afsluttet endnu? Næste skridt er at se, hvem der har denne html, og bruge !gcroot.

0:000> !gcroot 0000001f19002fcf0
Tråd 5a10:
    0000004d10dfe250 00007ffb18172a1b WindowsFormsApp4.Form1.button1_Click(System.Object, System.EventArgs) [E:\net5\ConsoleApp1\WindowsFormsApp4\Form1.cs @ 26]
        rbp+10: 0000004d10dfe2b0
            -> 000001f180007f78 WindowsFormsApp4.Form1
            -> 000001f180070d68 System.ComponentModel.EventHandlerList
            -> 000001f180071718 System.ComponentModel.EventHandlerList+ListEntry
            -> 000001f1800716d8 System.EventHandler
            -> 000001f1800716b0 System.Windows.Forms.ApplicationContext
            -> 0000001f180071780 System.EventHandler
            -> 000001f18006ab38 System.Windows.Forms.Application+ThreadContext
            -> 000001f18006b140 System.Windows.Forms.Application+MarshalingControl
            -> 000001f18016c9c8 System.Collections.Kø
            -> 000001f18016ca00 System.Objekt[]
            -> 000001f18016c948 System.Windows.Forms.Control+ThreadMethodEntry
            -> 000001f18016c8b8 System.Objekt[]
            -> 000001f1800e6f80 System. Handling
            -> 000001f1800e6f60 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner
            -> 000001f1800a77d0 WindowsFormsApp4.Form1+<GetJsonAsync>d__2
            -> 000001f1800b4e50 System.Threading.Tasks.Task'1[[System.String, mscorlib]]
            -> 000001f19002fcf0 System.Streng

Fandt 1 unik rødder (løb '! GCRoot - alle ' for at se alle rødder).
Ud fra outputresultaterne er denne System.String endelig holdt af WindowsFormsApp4.Form1 i 5a10-tråden, og du kan bruge !t til at verificere, hvilken tråd 5a10 er.

0:000> !t Lås  
       ID OSID trådOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
   0 1 5a10 000001f1f1b01200 2026020 Foregriber 000001F1800E70E70E8:000001F1800E7FD0 000001f1f1ad5b90 0 STA
   2 2 712c 000001f1f1b2a270 2b220 Forebyggende 00000000000000000:00000000000000000 0000001f1f1ad5b90 0 MTA (Finalizer)
Jeg går, 5a10 viste sig at være hovedtråden, det var virkelig lidt forvirrende, hovedtråden sad fast, og tråden blev holdt af hovedtråden, helt uforklarligt.

3) Se efter udbrudspunkter
Stadig roligt tilbage og tænke over denne referencekæde, fandt jeg ud af, at der er en kø her: -> 000001f18016c9c8 System.Collections.Queue, jeg har en idé, jeg kan fejlfinde kildekoden ved at placere et breakpoint i køen, og værktøjet bruger DnSpy, bare gør det.



Som du kan se på figuren, bruges tråd 10, når man går ind i køen, hvilket betyder, at strengen endnu ikke holdes af hovedtråden på nuværende tidspunkt.



Fra diagrammet kan man se, at den kontinuerlige opgave endelig planlægges ved at WindowsFormsSynchronizationContext.Post ind i Køen under Kontrol, og dataene i denne kø skal udføres af UI-tråden, så der er følgende dialog:

Hovedtråd: Opgavebror, hvornår bliver du færdig med at udføre den? Jeg venter på, at du fuldfører signalet?

opgave:Bror, hvis du ikke henretter mig, hvordan kan jeg så gøre det færdigt?

Hovedtråd:Nå...

Sammenfattende: fortsættelsesopgaven er nået til køen, der venter på, at hovedtråden skal eksekvere, og på dette tidspunkt er hovedtråden stunet og har ventet på, at fortsættelsesopgaven skal fuldføre=true, problemet er her: hvordan kan fortsættelsesopgaven ikke udføres Fuldført=sand? Så de er sådan her.

Tre: Hvordan man knækker den

Når man kender årsag og virkning, er denne metode til knækking simpel og groft opdelt i to typer.

1. Det er forbudt at lægge en fortsættelsesopgave i en kø

For at afskære denne sti er implikationen, at trådpoolen selv afslutter opgaven, så UI-tråden kan registrere, at opgaven er fuldført, og til sidst kan UI-tråden hente den endelige html, som er at tilføje ConfigureAwait(false) efter await, som følger:



2. Bloker hovedtråden

Hvis hovedtråden ikke er blokeret, kan hovedtråden frit hente de opgaver, der skal udføres i Control.Queue, og metoden er meget simpel, bare tilføj await før GetJsonAsync.



Tre: Resumé

Konklusionen er, at du skal praktisere mere selv, teoretisk viden bliver tvunget ind i dig af andre, uanset om den er rigtig eller forkert, faktisk har du ingen bund i dit hjerte, praktisk verifikation er det, der virkelig tilhører dig, og det er svært at glemme, at du trods alt virkelig har oplevet, øvet og verificeret.

Oprindelig:Hyperlink-login er synlig.





Tidligere:Docker modificerer og begrænser container-CPU, hukommelse og andre ressourcer
Næste:JS-arrays er forskellen og brugen af alle og nogle
Opslået den 8-8-2022 17:01:32 |
Lær at lære...
Opslået den 2022-9-2 11:39:19 |
Lær lidt
Ansvarsfraskrivelse:
Al software, programmeringsmaterialer eller artikler udgivet af Code Farmer Network er kun til lærings- og forskningsformål; Ovenstående indhold må ikke bruges til kommercielle eller ulovlige formål, ellers skal brugerne bære alle konsekvenser. Oplysningerne på dette site kommer fra internettet, og ophavsretstvister har intet med dette site at gøre. Du skal slette ovenstående indhold fuldstændigt fra din computer inden for 24 timer efter download. Hvis du kan lide programmet, så understøt venligst ægte software, køb registrering og få bedre ægte tjenester. Hvis der er nogen overtrædelse, bedes du kontakte os via e-mail.

Mail To:help@itsvse.com