Programmering

Bedste fremgangsmåder til .Net-trådsynkronisering

Synkronisering er et koncept, der bruges til at forhindre flere tråde i at få adgang til en delt ressource samtidigt. Du kan bruge den til at forhindre, at flere tråde påberåber et objekts egenskaber eller metoder samtidigt. Alt hvad du skal gøre er at synkronisere den blok med kode, der får adgang til den delte ressource eller synkronisere opkaldene til objektets egenskaber og medlemmer, så kun en tråd på et givet tidspunkt kan komme ind i det kritiske afsnit.

Denne artikel præsenterer en diskussion om begreberne relateret til synkronisering og trådsikkerhed i .Net og de bedste involverede fremgangsmåder.

Eksklusiv lås

Eksklusiv låsning bruges til at sikre, at en og kun en tråd på et givet tidspunkt kan komme ind i et kritisk afsnit. Du skal bruge en af ​​følgende til at implementere eksklusive låse i din applikation.

  • Lås - dette er en syntaktisk genvej til de statiske metoder i Monitor-klassen og bruges til at erhverve en eksklusiv lås på en delt ressource
  • Mutex - svarer til nøgleordet, bortset fra at det kan arbejde på tværs af flere processer
  • SpinLock - bruges til at erhverve en eksklusiv lås på en delt ressource ved at undgå trådkontekst-switch overhead

Du kan bruge de statiske metoder i Monitor-klassen eller låsenøgleordet til at implementere trådsikkerhed i dine applikationer. Både de statiske medlemmer af klassen Monitor og lås nøgleordene kan bruges til at forhindre samtidig adgang til en delt ressource. Lås nøgleordet er bare en genvej til implementering af synkronisering. Men når du har brug for at udføre komplekse operationer i et multitrådet program, kan metoderne Wait () og Pulse () i Monitor-klassen være nyttige.

Følgende kodestykke illustrerer, hvordan du kan implementere synkronisering ved hjælp af klassen Monitor.

privat statisk readonly objekt lockObj = nyt objekt ();

       statisk ugyldigt Main (streng [] args)

        {

Monitor.Enter (lockObj);

                       prøve

            {

// Noget kode

            }

            langt om længe

            {

Monitor.Exit (lockObj);

            }

        }

Den ækvivalente kode, der bruger lås nøgleordet, vil ligne dette:

    privat statisk readonly objekt lockObj = nyt objekt ();

statisk ugyldigt Main (streng [] args)

        {  

prøve

            {

lås (lockObj)

                {

// Noget kode

                }             

            }

langt om længe

            {

// Du kan frigive alle ressourcer her

            }

        }

Du kan drage fordel af Mutex-klassen til at implementere synkronisering, der kan spænde over processer. Bemærk, at en lås, der er erhvervet af en Mutex, i lighed med låseanmeldelsen kun kan frigøres fra den samme tråd, der blev brugt til at erhverve låsen. At erhverve og frigøre låse ved hjælp af Mutex er forholdsvis langsommere end at gøre det samme ved hjælp af låseanmeldelsen.

Hovedidéen bag SpinLock er at minimere omkostningerne ved kontekstskift mellem tråde - hvis en tråd kan vente eller dreje et stykke tid, indtil den kan erhverve en lås på en delt ressource, kan omkostningerne involveret i kontekstskift mellem tråde undgås . Når det kritiske afsnit udfører en minimal mængde arbejde, kan det være en god kandidat til en SpinLock.

Ikke-eksklusiv lås

Du kan drage fordel af ikke-eksklusiv låsning for at begrænse samtidighed. For at implementere ikke-eksklusive låse kan du bruge et af følgende.

  • Semaphore - bruges til at begrænse antallet af tråde, der kan have adgang til en delt ressource samtidigt. I det væsentlige bruges det samtidig til at begrænse antallet af forbrugere til en bestemt delt ressource.
  • SemaphoreSlim - et hurtigt, let alternativ til Semaphore-klassen til implementering af ikke-eksklusive låse.
  • ReaderWriterLockSlim - ReaderWriterLockSlim-klassen blev introduceret i .Net Framework 3.5 som erstatning for ReaderWriterLock-klassen.

Du kan bruge klassen ReaderWriterLockSlim til at erhverve en ikke-eksklusiv lås på en delt ressource, der har brug for hyppige læsninger, men sjældne opdateringer. Så i stedet for en gensidigt eksklusiv lås på en delt ressource, der har brug for hyppige læsninger og sjældne opdateringer, kan du bruge denne klasse til at erhverve en læselås på den delte ressource og en eksklusiv skrivelås på den.

Fastlåsning

Du bør undgå at bruge en låseanmeldelse på typen eller bruge udsagn som lås (dette) til at implementere synkronisering i din applikation, da dette kan resultere i deadlocks. Bemærk, at blokeringer også kan opstå, hvis du holder låsen erhvervet på en delt ressource i længere tid. Du bør ikke bruge uforanderlige typer i dine låseanmeldelser. Som et eksempel, bør du undgå at bruge et strengobjekt som en nøgle i din låsestatus. Du bør undgå at bruge låseanmeldelsen på en offentlig type - det er en god praksis at låse på private eller beskyttede objekter, der ikke er interneret. I det væsentlige opstår en blokering, når flere tråde venter på hinanden for at frigøre lås på en delt ressource. Du kan henvise til denne MSDN-artikel for at vide mere om deadlocks.