Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
.NET offre un intervallo di tipi che è possibile usare per sincronizzare l'accesso a una risorsa condivisa o coordinare l'interazione tra thread.
Importante
Usare la stessa istanza primitiva di sincronizzazione per proteggere l'accesso di una risorsa condivisa. Se si usano istanze primitive di sincronizzazione diverse per proteggere la stessa risorsa, è possibile aggirare la protezione fornita da una primitiva di sincronizzazione.
Classe WaitHandle e tipi di sincronizzazione leggeri
Più primitive di sincronizzazione .NET derivano dalla System.Threading.WaitHandle classe , che incapsula un handle di sincronizzazione del sistema operativo nativo e usa un meccanismo di segnalazione per l'interazione tra thread. Tali classi includono:
- System.Threading.Mutex, che concede l'accesso esclusivo a una risorsa condivisa. Il mutex è considerato libero se non è posseduto da alcun thread.
- System.Threading.Semaphore, che limita il numero di thread che possono accedere a una risorsa condivisa o a un pool di risorse contemporaneamente. Lo stato di un semaforo è impostato su segnalato quando il conteggio è maggiore di zero e non firmato quando il conteggio è zero.
- System.Threading.EventWaitHandle, che rappresenta un evento di sincronizzazione del thread e può trovarsi in uno stato segnalato o non segnalato.
- System.Threading.AutoResetEvent, che deriva da EventWaitHandle e, quando segnalato, reimposta automaticamente uno stato non segnalato dopo il rilascio di un singolo thread in attesa.
- System.Threading.ManualResetEvent, che deriva da EventWaitHandle e, quando segnalato, rimane in uno stato segnalato fino a quando non viene chiamato il Reset metodo .
In .NET Framework, poiché WaitHandle deriva da System.MarshalByRefObject, questi tipi possono essere usati per sincronizzare le attività dei thread attraverso i limiti del dominio applicazione.
In .NET Framework, .NET Core e .NET 5+, alcuni di questi tipi possono rappresentare handle di sincronizzazione di sistema denominati, visibili in tutto il sistema operativo e possono essere usati per la sincronizzazione tra processi:
- Mutex
- Semaphore (su Windows)
- EventWaitHandle (su Windows)
Per ulteriori informazioni, consultare il riferimento all'WaitHandle API.
I tipi di sincronizzazione leggeri non si basano sugli handle del sistema operativo sottostanti e in genere offrono prestazioni migliori. Tuttavia, non possono essere usate per la sincronizzazione tra processi. Usare questi tipi per la sincronizzazione dei thread all'interno di un'applicazione.
Alcuni di questi tipi sono alternative ai tipi derivati da WaitHandle. Ad esempio, SemaphoreSlim è un'alternativa leggera a Semaphore.
Sincronizzazione dell'accesso a una risorsa condivisa
.NET offre una gamma di primitive di sincronizzazione per controllare l'accesso a una risorsa condivisa da più thread.
Classe Monitor
La System.Threading.Monitor classe concede l'accesso reciproco esclusivo a una risorsa condivisa acquisendo o rilasciando un blocco sull'oggetto che identifica la risorsa. Mentre si tiene un blocco, il thread che contiene il blocco può acquisire e rilasciare nuovamente il blocco. Qualsiasi altro thread è bloccato dall'acquisire il lock e il metodo Monitor.Enter attende fino al rilascio del lock. Il Enter metodo acquisisce un blocco che è stato rilasciato. È anche possibile usare il Monitor.TryEnter metodo per specificare la quantità di tempo durante la quale un thread tenta di acquisire un blocco. Poiché la Monitor classe ha affinità di thread, il thread che ha acquisito un blocco deve rilasciare il blocco chiamando il Monitor.Exit metodo .
È possibile coordinare l'interazione dei thread che acquisiscono un blocco sullo stesso oggetto usando i Monitor.Waitmetodi , Monitor.Pulsee Monitor.PulseAll .
Per ulteriori informazioni, consultare il riferimento all'Monitor API.
Annotazioni
Usare l'istruzione lock in C# e l'istruzione SyncLock in Visual Basic per sincronizzare l'accesso a una risorsa condivisa anziché usare direttamente la Monitor classe . Tali istruzioni vengono implementate utilizzando i metodi Enter e Exit e un blocco try…finally
per garantire che il blocco acquisito venga sempre rilasciato.
Classe Mutex
La System.Threading.Mutex classe, ad esempio Monitor, concede l'accesso esclusivo a una risorsa condivisa. Utilizzare uno degli overload del metodo Mutex.WaitOne per richiedere la proprietà di un mutex. Come Monitor, Mutex ha affinità di thread e il thread che ha acquisito un mutex deve rilasciarlo chiamando il metodo Mutex.ReleaseMutex.
A differenza di Monitor, la classe può essere usata per la Mutex sincronizzazione tra processi. Per fare ciò, usa un mutex con nome, visibile in tutto il sistema operativo. Per creare un'istanza mutex denominata, usare un costruttore Mutex che specifica un nome. È anche possibile chiamare il metodo Mutex.OpenExisting per aprire un mutex di sistema già esistente e denominato.
Per altre informazioni, vedere l'articolo Mutexes e le informazioni di riferimento sulle Mutex API.
Struttura SpinLock
La System.Threading.SpinLock struttura, ad esempio Monitor, concede l'accesso esclusivo a una risorsa condivisa in base alla disponibilità di un blocco. Quando SpinLock tenta di acquisire un blocco non disponibile, attende in un ciclo, verificando ripetutamente fino a quando il blocco non diventa disponibile.
Per altre informazioni sui vantaggi e sugli svantaggi dell'uso del blocco spin, vedere l'articolo SpinLock e le informazioni di riferimento sulle SpinLock API.
Classe ReaderWriterLockSlim
La System.Threading.ReaderWriterLockSlim classe concede l'accesso esclusivo a una risorsa condivisa per la scrittura e consente a più thread di accedere contemporaneamente alla risorsa per la lettura. È possibile usare ReaderWriterLockSlim per sincronizzare l'accesso a una struttura di dati condivisa che supporta operazioni di lettura thread-safe, ma richiede l'accesso esclusivo per eseguire operazioni di scrittura. Quando un thread richiede l'accesso esclusivo ,ad esempio chiamando il ReaderWriterLockSlim.EnterWriteLock metodo , le richieste di lettura e scrittura successive bloccano fino a quando tutti i lettori esistenti non hanno chiuso il blocco e il writer è entrato e ha chiuso il blocco.
Per ulteriori informazioni, consultare il riferimento all'ReaderWriterLockSlim API.
Classi Semaphore e SemaphoreSlim
Le System.Threading.Semaphore classi e System.Threading.SemaphoreSlim limitano il numero di thread che possono accedere a una risorsa condivisa o a un pool di risorse contemporaneamente. Thread aggiuntivi che richiedono la risorsa attendono fino a quando qualsiasi thread rilascia il semaforo. Poiché il semaforo non ha affinità di thread, un thread può acquisire il semaforo e un altro può rilasciarlo.
SemaphoreSlim è un'alternativa leggera a Semaphore e può essere usata solo per la sincronizzazione all'interno di un singolo limite di processo.
In Windows è possibile usare Semaphore per la sincronizzazione tra processi. A tale scopo, creare un'istanza Semaphore che rappresenta un semaforo di sistema denominato usando uno dei costruttori Semaphore che specifica un nome o il Semaphore.OpenExisting metodo . SemaphoreSlim non supporta semafori di sistema denominati.
Per altre informazioni, vedere l'articolo Semaphore e SemaphoreSlim e le informazioni di riferimento sulle Semaphore API o SemaphoreSlim .
Interazione tra thread o segnalazione
L'interazione tra thread (o segnalazione di thread) significa che un thread deve attendere la notifica o un segnale da uno o più thread per continuare. Ad esempio, se il thread A chiama il Thread.Join metodo del thread B, il thread A viene bloccato fino al completamento del thread B. Le primitive di sincronizzazione descritte nella sezione precedente forniscono un meccanismo diverso per la segnalazione: rilasciando un blocco, un thread notifica a un altro thread che può continuare acquisendo il blocco.
Questa sezione descrive i costrutti di segnalazione aggiuntivi forniti da .NET.
Classi EventWaitHandle, AutoResetEvent, ManualResetEvent e ManualResetEventSlim
La System.Threading.EventWaitHandle classe rappresenta un evento di sincronizzazione del thread.
Un evento di sincronizzazione può trovarsi in uno stato non segnalato o segnalato. Quando lo stato di un evento non è segnalato, un thread che chiama l'overload dell'evento WaitOne viene bloccato finché un evento non viene segnalato. Il EventWaitHandle.Set metodo imposta lo stato di un evento su segnalato.
Il comportamento di un oggetto EventWaitHandle segnalato dipende dalla modalità di reimpostazione:
- Un EventWaitHandle creato con il flag EventResetMode.AutoReset si reimposta automaticamente dopo il rilascio di un singolo thread in attesa. È come un tornello che permette il passaggio di un solo flusso alla volta quando viene attivato. La System.Threading.AutoResetEvent classe , che deriva da EventWaitHandle, rappresenta tale comportamento.
- Un EventWaitHandle oggetto creato con il EventResetMode.ManualReset flag rimane segnalato fino a quando non viene chiamato il relativo Reset metodo. È come un cancello chiuso fino a quando non viene segnalato e poi rimane aperto fino a quando qualcuno lo chiude. La System.Threading.ManualResetEvent classe , che deriva da EventWaitHandle, rappresenta tale comportamento. La System.Threading.ManualResetEventSlim classe è un'alternativa leggera a ManualResetEvent.
In Windows è possibile usare EventWaitHandle per la sincronizzazione tra processi. A tale scopo, creare un'istanza EventWaitHandle che rappresenta un evento di sincronizzazione del sistema denominato utilizzando uno dei costruttori EventWaitHandle che specifica un nome o il EventWaitHandle.OpenExisting metodo .
Per altre informazioni, vedere l'articolo EventWaitHandle . Per informazioni di riferimento sull'API, vedere EventWaitHandle, AutoResetEvent, ManualResetEvente ManualResetEventSlim.
Classe CountdownEvent
La System.Threading.CountdownEvent classe rappresenta un evento che viene impostato quando il conteggio è zero. Mentre CountdownEvent.CurrentCount è maggiore di zero, un thread che chiama CountdownEvent.Wait viene bloccato. Chiamare CountdownEvent.Signal per decrementare il conteggio di un evento.
A differenza di ManualResetEvent o ManualResetEventSlim, che è possibile usare per sbloccare più thread con un segnale da un thread, è possibile usare CountdownEvent per sbloccare uno o più thread con segnali provenienti da più thread.
Per altre informazioni, vedere l'articolo CountdownEvent e le informazioni di riferimento sulle CountdownEvent API.
Classe barriera
La System.Threading.Barrier classe rappresenta una barriera di esecuzione del thread. Un thread che chiama il Barrier.SignalAndWait metodo segnala che ha raggiunto la barriera e attende che altri thread partecipanti raggiungano la barriera. Quando tutti i thread dei partecipanti raggiungono la barriera, essi procedono e la barriera viene reimpostata e può essere utilizzata di nuovo.
È possibile usare Barrier quando uno o più thread richiedono i risultati di altri thread prima di procedere alla fase di calcolo successiva.
Per altre informazioni, vedere l'articolo Barriera e le informazioni di riferimento sulle Barrier API.
Classe interbloccata
La System.Threading.Interlocked classe fornisce metodi statici che eseguono semplici operazioni atomica su una variabile. Tali operazioni atomiche includono addizione, incremento e decremento, scambio e scambio condizionale che dipende da un confronto e operazione di lettura di un valore intero a 64 bit.
Per ulteriori informazioni, consultare il riferimento all'Interlocked API.
Struttura SpinWait
La struttura System.Threading.SpinWait offre supporto per l'attesa basata sullo spin. Potrebbe essere necessario usarlo quando un thread deve attendere che venga segnalato un evento o una condizione da soddisfare, ma quando si prevede che il tempo di attesa effettivo sia inferiore al tempo di attesa richiesto usando un handle di attesa o bloccando altrimenti il thread. Usando SpinWait, è possibile specificare un breve periodo di tempo per ruotare durante l'attesa e quindi restituire (ad esempio, in attesa o in sospensione) solo se la condizione non è stata soddisfatta nell'ora specificata.
Per altre informazioni, vedere l'articolo SpinWait e le informazioni di riferimento sulle SpinWait API.