Semaforo - Qual è l'uso del conteggio iniziale?


96

http://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim.aspx

Per creare un semaforo, devo fornire un conteggio iniziale e un conteggio massimo. MSDN afferma che un conteggio iniziale è:

Il numero iniziale di richieste per il semaforo che possono essere concesse contemporaneamente.

Mentre afferma che il conteggio massimo è

Il numero massimo di richieste per il semaforo che possono essere concesse contemporaneamente.

Posso capire che il conteggio massimo è il numero massimo di thread che possono accedere a una risorsa contemporaneamente. Ma a cosa serve il conteggio iniziale?

Se creo un semaforo con un conteggio iniziale di 0 e un conteggio massimo di 2, nessuno dei miei thread del pool di thread è in grado di accedere alla risorsa. Se imposto il conteggio iniziale come 1 e il conteggio massimo come 2, solo il thread del pool di thread può accedere alla risorsa. È solo quando imposto sia il conteggio iniziale che il conteggio massimo su 2, 2 thread sono in grado di accedere alla risorsa contemporaneamente. Quindi, sono davvero confuso sul significato del conteggio iniziale?

SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0, 2); //all threadpool threads wait
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 2);//only one thread has access to the resource at a time
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(2, 2);//two threadpool threads can access the resource concurrently

Risposte:


83

Sì, quando il numero iniziale è impostato su 0, tutti i thread saranno in attesa mentre si incrementa la proprietà "CurrentCount". Puoi farlo con Release () o Release (Int32).

Release (...): incrementerà il contatore del semaforo

Aspetta (...) - lo diminuirà

Non è possibile incrementare il contatore (proprietà "CurrentCount") maggiore del conteggio massimo impostato nell'inizializzazione.

Per esempio:

SemaphoreSlim^ s = gcnew SemaphoreSlim(0,2); //s->CurrentCount = 0
s->Release(2); //s->CurrentCount = 2
...

s->Wait(); //Ok. s->CurrentCount = 1
...

s->Wait(); //Ok. s->CurrentCount = 0
...

s->Wait(); //Will be blocked until any of the threads calls Release()

1
Il tuo codice sarà presentato meglio nella risposta piuttosto che come commento.
ChrisF

16
LOL è probabilmente la quinta volta che raggiungo questa stessa risposta perché la documentazione del costruttore mi confonde sempre su quali valori impostare. Saluti
BlueStrat

73

Quindi, sono davvero confuso sul significato del conteggio iniziale?

Un punto importante che può aiutare qui è che Waitdiminuisce il conteggio del semaforo e lo Releaseincrementa.

initialCountè il numero di accessi alle risorse che saranno consentiti immediatamente. O, in altre parole, è il numero di volte che Waitpuò essere chiamato senza bloccare immediatamente dopo l'istanza del semaforo.

maximumCountè il conteggio più alto che il semaforo può ottenere. È il numero di volte che Releasepuò essere chiamato senza generare un'eccezione assumendo che il initialCountconteggio sia zero. Se initialCountè impostato sullo stesso valore, la maximumCountchiamata Releaseimmediatamente dopo l'istanza del semaforo genererà un'eccezione.


20
Questo è così utile! Stavo pensando ai semafori all'indietro, poiché in initialCount è il numero di risorse BLOCCATE iniziali, non il numero di risorse immediatamente disponibili. Grazie.
Philip Tenn

5
@PhilipTenn, sono d'accordo - la documentazione non è chiara al riguardo
BlueStrat

Ho accettato di cambiare il nome della variabile o aggiornare i documenti
IronHide

@ Sandbox dovresti accettare questa risposta IMO, poiché spiega davvero il significato del initialCountparametro.
Michał Turczyn

9

Quanti thread vuoi poter accedere alla risorsa contemporaneamente? Imposta il conteggio iniziale su quel numero. Se quel numero non aumenterà mai per tutta la durata del programma, imposta anche il conteggio massimo su quel numero. In questo modo, se hai un errore di programmazione nel modo in cui rilasci la risorsa, il tuo programma andrà in crash e te lo farà sapere.

(Ci sono due costruttori: uno che accetta solo un valore iniziale e uno che in aggiunta accetta il conteggio massimo. Utilizza quello appropriato.)


2

Se desideri che nessun thread acceda alla tua risorsa per un po 'di tempo, passi il conteggio iniziale come 0 e quando desideri concedere l'accesso a tutti subito dopo aver creato il semaforo, passi il valore del conteggio iniziale uguale al conteggio massimo . Per esempio:

hSemaphore = CreateSemaphoreA(NULL, 0, MAX_COUNT, NULL) ;

//Do something here
//No threads can access your resource

ReleaseSemaphore(hSemaphore, MAX_COUNT, 0) ;

//All threads can access the resource now

Come citato nella documentazione MSDN: "Un altro utilizzo di ReleaseSemaphore è durante l'inizializzazione di un'applicazione. L'applicazione può creare un semaforo con un conteggio iniziale pari a zero. Questo imposta lo stato del semaforo su non segnalato e impedisce a tutti i thread di accedere alla risorsa protetta. Quando l'applicazione termina la sua inizializzazione, utilizza ReleaseSemaphore per aumentare il conteggio al valore massimo, per consentire il normale accesso alla risorsa protetta. "


Scusa, ti ho fornito l'esempio in C ++ anche se posso chiarire il dubbio.
Abhineet

1

In questo modo, quando il thread corrente crea il semaforo, potrebbe richiedere alcune risorse dall'inizio.


Quindi, vuoi dire che quando voglio che due thread di lavoro accedano alla risorsa dovrei cambiare il conteggio iniziale?
Sandbox

No. È il thread corrente che rivendica un conteggio. Se non si desidera che il thread corrente rivendichi alcun accesso, passare 0 o utilizzare l'overload con un parametro.
Erno

-1

I semafori possono essere utilizzati per proteggere un pool di risorse . Usiamo pool di risorse per riutilizzare cose costose da creare , come le connessioni al database.

Quindi il conteggio iniziale si riferisce al numero di risorse disponibili nel pool all'inizio di un processo. Quando leggi il initialCountcodice nel codice dovresti pensare in termini di quanto impegno iniziale stai mettendo nella creazione di questo pool di risorse.

Sono davvero confuso sul significato del conteggio iniziale?

Initial count = Upfront cost

In quanto tale, a seconda del profilo di utilizzo dell'applicazione, questo valore può avere un effetto notevole sulle prestazioni dell'applicazione. Non è solo un numero arbitrario.

Dovresti pensare attentamente a ciò che stai creando, quanto sono costosi da creare e quanti ne hai bisogno subito. Dovresti letteralmente essere in grado di rappresentare graficamente il valore ottimale per questo parametro e dovresti probabilmente pensare di renderlo configurabile in modo da poter adattare le prestazioni del processo al momento in cui viene eseguito.


-2

Come spiega MSDN nella sezione Osservazioni:

Se initialCount è minore di maximumCount, l'effetto è lo stesso che se il thread corrente avesse chiamato WaitOne (maximumCount meno initialCount) volte. Se non si desidera riservare alcuna voce per il thread che crea il semaforo, utilizzare lo stesso numero per maximumCount e initialCount.

Quindi, se il conteggio iniziale è 0 e il massimo è 2, è come se WaitOne fosse stato chiamato due volte dal thread principale, quindi abbiamo raggiunto la capacità (il conteggio dei semafori è 0 ora) e nessun thread può entrare in Semaphore. Allo stesso modo, se il conteggio iniziale è 1 e il massimo è 2, WaitOnce è stato chiamato una volta e solo un thread può entrare prima di raggiungere nuovamente la capacità e così via.

Se viene utilizzato 0 per il conteggio iniziale, è sempre possibile chiamare Release (2) per aumentare il conteggio dei semafori al massimo per consentire al numero massimo di thread di acquisire risorse.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.