Denne artikkelen er en speilartikkel om maskinoversettelse, vennligst klikk her for å hoppe til originalartikkelen.

Utsikt: 6277|Svare: 2

[Kommunikasjon] [Snu] En setning Oppgave. Resultatet blir låst, hvordan ellers skrive denne koden?

[Kopier lenke]
Publisert 7.08.2022 kl. 21:11:58 | | | |
1: Bakgrunn

1. Fortell historier

For noen dager siden, da jeg indekserte artikkelen om .NET Advanced Debugging til github, fant jeg en interessant kommentar, se artikkelen for detaljer, skjermbildet er som følger:



Det betyr sannsynligvis at å kjøre Task.Result under hovedtråden i Winform vil føre til en deadlock, jeg så også på referanselinken på bildet, Stephen er den absolutte sjefen, men denne artikkelen handler hovedsakelig om indoktrinering av et stort avsnitt med tekst, og den lar deg egentlig ikke 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 spilt Winform på mange år, og jeg klarer ikke å finne ut om det vil gjøre det, i hvert fall ikke på konsollen.

Koden er veldig enkel, kjør programmet, klikk klikk, og ganske riktig, grensesnittet sitter fast, noe som er litt utrolig.

2. Se etter årsaken til fastlåst situasjon

Deretter, skynd deg og legg windbg til prosessen for å finne ut av det.

1) Se på hovedtråden
Grensesnittet reagerer ikke, så naturligvis sitter hovedtråden fast, så du må se på hva hovedtråden gjør akkurat nå. Bruk kommandoen ~0s + !clrstack.

0:000> !clrstack
OS-tråd-ID: 0x5a10 (0)
        Child SP IP-samtalested
0000004d10dfde00 00007ffb889a10e4 [GCFrame: 0000004d10dfde00]
0000004d10dfdf28 00007ffb889a10e4 [HelperMethodFrame_1OBJ: 0000004d10dfdf28] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Objekt)
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 (boolsk)
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.Message ByRef)
0000004d10dfe540 00007ffb3a0b0c97 System.Windows.Forms.ButtonBase.WndProc(System.Windows.Forms.Message 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]
Fra stack-utgangen sitter hovedtråden endelig fast på Monitor.ObjWait under Task.Result, noe som betyr at den ennå ikke har hentet den siste jsonString, noe som er veldig merkelig, det har gått flere minutter, er det et problem med nettverket? Nettet mitt er 100 meter fullt av ildkraft...

2) Hvor ble det av jsonString?
Hvis jsonString finnes på den administrerte heapen, betyr det at det er noe i programmet som gjør at resultatet blir forsinket, bruk kommandoen !dumpheap -type String -min 8500 + !do 000001f19002fcf0 for å se, som vist i figuren nedenfor:



Fra figuren kan det tydelig sees at HTML er tilbake, siden alt er tilbake, hvorfor er ikke Task.Result ferdig ennå? Neste steg er å se hvem som har denne html-en og bruke !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.KomponentModell.EventHandlerList
            -> 000001f180071718 System.KomponentModell.EventHandlerList+ListEntry
            -> 0000001f1800716d8 System.EventHandler
            -> 000001f1800716b0 System.Windows.Forms.ApplicationContext
            -> 000001f180071780 System.EventHandler
            -> 000001f18006ab38 System.Windows.Forms.Application+ThreadContext
            -> 000001f18006b140 System.Windows.Forms.Application+MarshalingControl
            -> 000001f18016c9c8 System.Samlinger.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

Fant 1 unike røtter (løp! GCRoot – alle for å se alle røtter).
Ut fra resultatene holdes denne System.String endelig av WindowsFormsApp4.Form1 i 5a10-tråden, og du kan bruke !t for å verifisere hvilken tråd 5a10 er.

0:000> !t Lås  
       ID OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
   0 1 5a10 000001f1f1b01200 2026020 Pre-emptive 000001F1800E70E8:000001F1800E7FD0 000001f1f1ad5b90 0 STA
   2 2 712c 000001f1f1b2a270 2b220 Preemptive 00000000000000000:000000000000000 0000001f1f1ad5b90 0 MTA (Finalizer)
Jeg sier, 5a10 viste seg å være hovedtråden, det var virkelig litt forvirrende, hovedtråden satt fast, og tråden ble holdt av hovedtråden, helt uforklarlig.

3) Se etter utbryterpunkter
Fortsatt mens jeg rolig tenker på denne referansekjeden, fant jeg ut at det finnes en kø her: -> 000001f18016c9c8 System.Collections.Queue, jeg har en idé, jeg kan feilsøke kildekoden ved å plassere et breakpoint i køen, og verktøyet bruker DnSpy, bare gjør det.



Som du kan se fra figuren, brukes tråd 10 når man går inn i kø, noe som betyr at strengen ennå ikke holdes av hovedtråden på dette tidspunktet.



Fra diagrammet kan man se at den kontinuerlige oppgaven til slutt planlegges av WindowsFormsSynchronizationContext.Post inn i køen under kontroll, og dataene i denne køen må utføres av UI-tråden, så det finnes følgende dialog:

Hovedtråd: Oppgavebror, når blir du ferdig med å utføre den? Jeg venter på at du skal fullføre signalet?

oppgave:Bror, hvis du ikke henretter meg, hvordan kan jeg da fullføre det?

Hovedtråd:Oh...

Oppsummert: fortsettelsesoppgaven har nådd køen som venter på at hovedtråden skal kjøres, og på dette tidspunktet er hovedtråden sjokkert og har ventet på at fortsettelsesoppgaven skal fullføre=true, problemet er her: hvordan kan fortsettelsesoppgaven ikke utføres Complete=true? Så de er slik.

Tre: Hvordan knekke den

Med kjennskap til årsak og virkning er denne metoden for sprekking enkel, grovt delt inn i to typer.

1. Det er forbudt å legge en fortsettelsesoppgave i en kø

For å kutte denne veien, er implikasjonen at trådpoolen avslutter oppgaven alene, slik at UI-tråden kan registrere at oppgaven er fullført, og til slutt UI-tråden kan hente den endelige html-en, som er å legge til ConfigureAwait(false) etter await, som følger:



2. Blokker hovedtråden

Hvis hovedtråden ikke er blokkert, kan hovedtråden fritt hente oppgavene som må utføres i Control.Queue, og metoden er veldig enkel, bare legg til await før GetJsonAsync.



Tre: Sammendrag

Konklusjonen er å gjøre mer av din egen praktiske praksis, teoretisk kunnskap blir tvunget inn i deg av andre, enten det er rett eller galt, faktisk har du ingen bunn i hjertet, praktisk verifisering er det som virkelig tilhører deg, og det er vanskelig å glemme, tross alt har du virkelig opplevd, praktisert og verifisert.

Original:Innloggingen med hyperkoblingen er synlig.





Foregående:Docker modifiserer og begrenser container-CPU, minne og andre ressurser
Neste:JS-arrayer er forskjellen og bruken av alle og noen
Publisert 2022-8-8 17:01:32 |
Lær å lære...
Publisert 2022-9-2 11:39:19 |
Lær litt
Ansvarsfraskrivelse:
All programvare, programmeringsmateriell eller artikler publisert av Code Farmer Network er kun for lærings- og forskningsformål; Innholdet ovenfor skal ikke brukes til kommersielle eller ulovlige formål, ellers skal brukerne bære alle konsekvenser. Informasjonen på dette nettstedet kommer fra Internett, og opphavsrettstvister har ingenting med dette nettstedet å gjøre. Du må fullstendig slette innholdet ovenfor fra datamaskinen din innen 24 timer etter nedlasting. Hvis du liker programmet, vennligst støtt ekte programvare, kjøp registrering, og få bedre ekte tjenester. Hvis det foreligger noen krenkelse, vennligst kontakt oss på e-post.

Mail To:help@itsvse.com