Condividi tramite


Semaforo e SemaforoSlim

La System.Threading.Semaphore classe rappresenta un semaforo denominato (a livello di sistema) o locale. Si tratta di un wrapper sottile intorno all'oggetto semaforo Win32. I semafori Win32 sono semafori contatori, che possono essere utilizzati per controllare l'accesso a un pool di risorse.

La SemaphoreSlim classe rappresenta un semaforo leggero e veloce che può essere usato per l'attesa all'interno di un singolo processo quando si prevede che i tempi di attesa siano molto brevi. SemaphoreSlim si basa il più possibile sulle primitive di sincronizzazione fornite da Common Language Runtime (CLR). Tuttavia, fornisce anche handle di attesa basati su kernel inizializzati in modo differito in base alle esigenze per supportare l'attesa su più semafori. SemaphoreSlim supporta anche l'uso di token di annullamento, ma non supporta semafori denominati o l'uso di un handle di attesa per la sincronizzazione.

Gestione di una risorsa limitata

I thread entrano nel semaforo chiamando il metodo WaitOne, ereditato dalla classe WaitHandle, nel caso di un oggetto System.Threading.Semaphore, o il metodo SemaphoreSlim.Wait o SemaphoreSlim.WaitAsync, nel caso di un oggetto SemaphoreSlim. Quando la chiamata ritorna, il conteggio sul semaforo viene decrementato. Quando un thread richiede l'accesso e il conteggio è zero, il thread si blocca. Quando i thread rilasciano il semaforo chiamando il Semaphore.Release metodo o SemaphoreSlim.Release , i thread bloccati possono entrare. Non esiste un ordine garantito, ad esempio first-in, first-out (FIFO) o last-in, first-out (LIFO), per i thread bloccati per l'ingresso nel semaforo.

Un thread può immettere più volte il semaforo chiamando ripetutamente il System.Threading.Semaphore metodo dell'oggetto WaitOne o il SemaphoreSlim metodo dell'oggetto Wait . Per rilasciare il semaforo, il thread può chiamare il metodo Semaphore.Release() o SemaphoreSlim.Release() dell'overload lo stesso numero di volte, oppure chiamare il metodo Semaphore.Release(Int32) o SemaphoreSlim.Release(Int32) dell'overload e specificare il numero di voci da rilasciare.

Semafori e identità del thread

I due tipi di semaforo non applicano l'identità del thread alle chiamate ai metodi WaitOne, Wait, Release e SemaphoreSlim.Release. Ad esempio, uno scenario di utilizzo comune per i semafori implica un thread produttore e un thread consumatore, con un thread che incrementa sempre il conteggio del semaforo e l'altro che lo decrementa sempre.

È responsabilità del programmatore assicurarsi che un thread non rilasci il semaforo troppe volte. Si supponga, ad esempio, che un semaforo abbia un conteggio massimo di due e che il thread A e il thread B entrino entrambi nel semaforo. Se un errore di programmazione nel thread B lo chiama Release due volte, entrambe le chiamate hanno esito positivo. Il conteggio sul semaforo è pieno e, quando il thread A infine chiama Release, viene generata un'eccezione SemaphoreFullException.

Semafori denominati

Il sistema operativo Windows consente ai semafori di avere nomi. Un semaforo denominato è valido per l'intero sistema. Cioè, una volta creato il semaforo denominato, esso è visibile a tutti i thread in tutti i processi. Pertanto, il semaforo con nome può essere usato per sincronizzare le attività dei processi e dei thread.

È possibile creare un Semaphore oggetto che rappresenta un semaforo di sistema denominato usando uno dei costruttori che specifica un nome.

Annotazioni

Poiché i semafori denominati sono a livello di sistema, è possibile che ci siano più oggetti Semaphore che rappresentano lo stesso semaforo denominato. Ogni volta che si chiama un costruttore o il Semaphore.OpenExisting metodo , viene creato un nuovo Semaphore oggetto . Se si specifica ripetutamente lo stesso nome, vengono creati più oggetti che rappresentano lo stesso semaforo denominato.

Fai attenzione quando utilizzi semafori nominati. Poiché sono a livello di sistema, un altro processo che usa lo stesso nome può accedere al semaforo in modo imprevisto. Il codice dannoso in esecuzione nello stesso computer potrebbe usarlo come base di un attacco Denial of Service.

Utilizzare la sicurezza del controllo di accesso per proteggere un Semaphore oggetto che rappresenta un semaforo denominato, preferibilmente usando un costruttore che specifica un System.Security.AccessControl.SemaphoreSecurity oggetto . È anche possibile applicare la sicurezza del controllo di accesso usando il Semaphore.SetAccessControl metodo , ma lascia una finestra di vulnerabilità tra il momento in cui viene creato il semaforo e l'ora in cui è protetta. La protezione dei semafori con la sicurezza del controllo di accesso consente di prevenire attacchi dannosi, ma non risolve il problema delle collisioni involontarie dei nomi.

Vedere anche