Översikt över synkroniseringsprimitiver
.NET innehåller en mängd olika typer som du kan använda för att synkronisera åtkomst till en delad resurs eller samordna trådinteraktion.
Viktigt!
Använd samma primitiva synkroniseringsinstans för att skydda åtkomsten till en delad resurs. Om du använder olika synkroniserings primitiva instanser för att skydda samma resurs kringgår du det skydd som tillhandahålls av en synkroniseringsprimett.
WaitHandle-klass och enkla synkroniseringstyper
Flera .NET-synkroniseringspri primitiver härleds från System.Threading.WaitHandle klassen, som kapslar in ett inbyggt operativsystemets synkroniseringshandtag och använder en signalmekanism för trådinteraktion. Dessa klasser omfattar:
- System.Threading.Mutex, som ger exklusiv åtkomst till en delad resurs. Tillståndet för en mutex signaleras om ingen tråd äger den.
- System.Threading.Semaphore, som begränsar antalet trådar som kan komma åt en delad resurs eller en resurspool samtidigt. Tillståndet för en semafor är inställt på att signaleras när dess antal är större än noll och nonsignaled när dess antal är noll.
- System.Threading.EventWaitHandle, som representerar en trådsynkroniseringshändelse och kan vara antingen i ett signalerat eller osignalat tillstånd.
- System.Threading.AutoResetEvent, som härleds från EventWaitHandle och, när den signaleras, återställs automatiskt till ett osignalat tillstånd efter att en enda väntande tråd släppts.
- System.Threading.ManualResetEvent, som härleds från EventWaitHandle och, när den signaleras, förblir i ett signalerat tillstånd tills Reset metoden anropas.
I .NET Framework, eftersom WaitHandle härleds från System.MarshalByRefObject, kan dessa typer användas för att synkronisera aktiviteter för trådar över programdomängränser.
I .NET Framework, .NET Core och .NET 5+, kan vissa av dessa typer representera namngivna systemsynkroniseringshandtag, som är synliga i hela operativsystemet och kan användas för synkronisering mellan processer:
- Mutex
- Semaphore (i Windows)
- EventWaitHandle (i Windows)
Mer information finns i API-referensen WaitHandle .
Enkla synkroniseringstyper förlitar sig inte på underliggande operativsystemhandtag och ger vanligtvis bättre prestanda. De kan dock inte användas för synkronisering mellan processer. Använd dessa typer för trådsynkronisering i ett program.
Vissa av dessa typer är alternativ till de typer som härleds från WaitHandle. Är till exempel SemaphoreSlim ett enkelt alternativ till Semaphore.
Synkronisering av åtkomst till en delad resurs
.NET tillhandahåller ett antal synkroniseringsprimitiver för att styra åtkomsten till en delad resurs av flera trådar.
Övervaka klass
Klassen System.Threading.Monitor ger ömsesidigt exklusiv åtkomst till en delad resurs genom att hämta eller frigöra ett lås på objektet som identifierar resursen. Medan ett lås hålls, kan tråden som innehåller låset igen hämta och frigöra låset. Alla andra trådar blockeras från att hämta låset Monitor.Enter och metoden väntar tills låset släpps. Metoden Enter hämtar ett frisläppt lås. Du kan också använda Monitor.TryEnter metoden för att ange hur lång tid en tråd försöker hämta ett lås under. Monitor Eftersom klassen har trådtillhörighet måste tråden som skaffade ett lås frigöra låset genom att anropa Monitor.Exit metoden.
Du kan samordna interaktionen mellan trådar som hämtar ett lås på samma objekt med hjälp Monitor.Waitav metoderna , Monitor.Pulseoch Monitor.PulseAll .
Mer information finns i API-referensen Monitor .
Kommentar
Använd låssatsen i C# och SyncLock-instruktioneni Visual Basic för att synkronisera åtkomst till en delad resurs i stället för att använda Monitor klassen direkt. Dessa instruktioner implementeras med metoderna Enter och Exit och ett try…finally
block för att säkerställa att det förvärvade låset alltid släpps.
Mutex-klass
Klassen System.Threading.Mutex , till exempel Monitor, ger exklusiv åtkomst till en delad resurs. Använd någon av metoden Mutex.WaitOne för att begära ägarskap för en mutex. Som Monitor, Mutex har trådtillhörighet och tråden som skaffade en mutex måste frigöra den genom att anropa Mutex.ReleaseMutex metoden.
Mutex Till skillnad från Monitorkan klassen användas för synkronisering mellan processer. För att göra det använder du en namngiven mutex, som är synlig i hela operativsystemet. Om du vill skapa en namngiven mutex-instans använder du en Mutex-konstruktor som anger ett namn. Du kan också anropa metoden för att öppna en befintlig namngiven Mutex.OpenExisting system mutex.
Mer information finns i artikeln Mutexes och API-referensen Mutex .
SpinLock-struktur
Strukturen System.Threading.SpinLock , till exempel Monitor, ger exklusiv åtkomst till en delad resurs baserat på tillgängligheten för ett lås. När SpinLock du försöker hämta ett lås som inte är tillgängligt väntar det i en loop och kontrollerar upprepade gånger tills låset blir tillgängligt.
Mer information om fördelarna och nackdelarna med att använda spinnlås finns i SpinLock-artikeln och API-referensen SpinLock .
ReaderWriterLockSlim-klass
Klassen System.Threading.ReaderWriterLockSlim ger exklusiv åtkomst till en delad resurs för skrivning och tillåter flera trådar att komma åt resursen samtidigt för läsning. Du kanske vill använda ReaderWriterLockSlim för att synkronisera åtkomst till en delad datastruktur som stöder trådsäkra läsåtgärder, men som kräver exklusiv åtkomst för att utföra skrivåtgärder. När en tråd begär exklusiv åtkomst (till exempel genom att anropa ReaderWriterLockSlim.EnterWriteLock metoden) blockeras efterföljande läsar- och skrivarbegäranden tills alla befintliga läsare har avslutat låset och skrivaren har angett och avslutat låset.
Mer information finns i API-referensen ReaderWriterLockSlim .
Semafor- och semaforSlimklasser
Klasserna System.Threading.Semaphore och System.Threading.SemaphoreSlim begränsar antalet trådar som kan komma åt en delad resurs eller en resurspool samtidigt. Ytterligare trådar som begär resursen väntar tills någon tråd släpper semaforen. Eftersom semaforen inte har trådtillhörighet kan en tråd hämta semaforen och en annan kan släppa den.
SemaphoreSlim är ett enkelt alternativ till Semaphore och kan endast användas för synkronisering inom en enda processgräns.
I Windows kan du använda Semaphore för synkronisering mellan processer. För att göra det skapar du en Semaphore instans som representerar en namngiven systemsemafor med hjälp av någon av de semaforkonstruktorer som anger ett namn eller en Semaphore.OpenExisting metod. SemaphoreSlim stöder inte namngivna systemskarforer.
Mer information finns i artikeln Semaphore och SemaphoreSlim och API-referensen Semaphore eller SemaphoreSlim .
Trådinteraktion eller signalering
Trådinteraktion (eller trådsignalering) innebär att en tråd måste vänta på meddelande, eller en signal, från en eller flera trådar för att kunna fortsätta. Om tråd A till exempel anropar Thread.Join metoden tråd B blockeras tråd A tills tråd B har slutförts. Synkroniseringens primitiver som beskrivs i föregående avsnitt ger en annan mekanism för signalering: genom att frigöra ett lås meddelar en tråd en annan tråd att den kan fortsätta genom att hämta låset.
I det här avsnittet beskrivs ytterligare signalkonstruktioner som tillhandahålls av .NET.
Klasser för EventWaitHandle, AutoResetEvent, ManualResetEvent och ManualResetEventSlim
Klassen System.Threading.EventWaitHandle representerar en trådsynkroniseringshändelse.
En synkroniseringshändelse kan antingen vara i ett osignalat eller signalerat tillstånd. När tillståndet för en händelse är osignalat blockeras en tråd som anropar händelsens WaitOne överbelastning tills en händelse signaleras. Metoden EventWaitHandle.Set anger tillståndet för en händelse till signalerad.
Beteendet för en EventWaitHandle som har signalerats beror på dess återställningsläge:
- En EventWaitHandle som skapas med EventResetMode.AutoReset flaggan återställs automatiskt efter att en enda väntande tråd har släppts. Det är som ett vändkors som bara tillåter en tråd genom varje gång den signaleras. Klassen System.Threading.AutoResetEvent , som härleds från EventWaitHandle, representerar det beteendet.
- En EventWaitHandle skapad med EventResetMode.ManualReset flaggan förblir signalerad tills dess Reset metod anropas. Det är som en grind som är stängd tills den signaleras och sedan förblir öppen tills någon stänger den. Klassen System.Threading.ManualResetEvent , som härleds från EventWaitHandle, representerar det beteendet. Klassen System.Threading.ManualResetEventSlim är ett enkelt alternativ till ManualResetEvent.
I Windows kan du använda EventWaitHandle för synkronisering mellan processer. För att göra det skapar du en EventWaitHandle instans som representerar en namngiven systemsynkroniseringshändelse med hjälp av någon av EventWaitHandle-konstruktorerna som anger ett namn eller en EventWaitHandle.OpenExisting metod.
Mer information finns i artikeln EventWaitHandle . Api-referensen finns i EventWaitHandle, AutoResetEvent, ManualResetEventoch ManualResetEventSlim.
CountdownEvent-klass
Klassen System.Threading.CountdownEvent representerar en händelse som anges när antalet är noll. Medan CountdownEvent.CurrentCount är större än noll blockeras en tråd som anropar CountdownEvent.Wait . Anropa CountdownEvent.Signal för att minska antalet händelser.
Till skillnad från ManualResetEvent eller ManualResetEventSlim, som du kan använda för att avblockera flera trådar med en signal från en tråd, kan du använda CountdownEvent för att avblockera en eller flera trådar med signaler från flera trådar.
Mer information finns i artikeln CountdownEvent och API-referensen CountdownEvent .
Barriärklass
Klassen System.Threading.Barrier representerar en trådkörningsbarriär. En tråd som anropar Barrier.SignalAndWait metoden signalerar att den nått barriären och väntar tills andra deltagartrådar når barriären. När alla deltagartrådar når barriären fortsätter de och barriären återställs och kan användas igen.
Du kan använda Barrier när en eller flera trådar kräver resultatet av andra trådar innan du fortsätter till nästa beräkningsfas.
Mer information finns i artikeln Barriär och API-referensen Barrier .
Sammanflätad klass
Klassen System.Threading.Interlocked innehåller statiska metoder som utför enkla atomiska åtgärder på en variabel. Dessa atomiska åtgärder omfattar addition, inkrement och minskning, utbyte och villkorligt utbyte som är beroende av en jämförelse och läsåtgärd av ett 64-bitars heltalsvärde.
Mer information finns i API-referensen Interlocked .
SpinWait-struktur
Strukturen System.Threading.SpinWait ger stöd för spinnbaserad väntan. Du kanske vill använda den när en tråd måste vänta på att en händelse ska signaleras eller ett villkor uppfylls, men när den faktiska väntetiden förväntas vara mindre än den väntetid som krävs med hjälp av ett väntehandtag eller genom att på annat sätt blockera tråden. Med hjälp SpinWaitav kan du ange en kort tidsperiod för att snurra medan du väntar och sedan ge (till exempel genom att vänta eller sova) endast om villkoret inte uppfylldes under den angivna tiden.
Mer information finns i spinwait-artikeln och API-referensen SpinWait .