Sémaphore - À quoi sert le comptage initial?

91

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

Pour créer un sémaphore, je dois fournir un nombre initial et un nombre maximum. MSDN déclare qu'un décompte initial est -

Nombre initial de requêtes pour le sémaphore pouvant être accordées simultanément.

Bien qu'il indique que le nombre maximum est

Le nombre maximum de requêtes pour le sémaphore qui peuvent être accordées simultanément.

Je peux comprendre que le nombre maximum est le nombre maximum de threads qui peuvent accéder à une ressource simultanément. Mais, à quoi sert le décompte initial?

Si je crée un sémaphore avec un nombre initial de 0 et un nombre maximum de 2, aucun de mes threads de threadpool ne peut accéder à la ressource. Si je règle le nombre initial sur 1 et le nombre maximum sur 2, seul le thread du pool de threads peut accéder à la ressource. Ce n'est que lorsque je règle le nombre initial et le nombre maximum sur 2, 2 threads peuvent accéder à la ressource simultanément. Donc, je suis vraiment confus sur la signification du décompte initial?

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
bac à sable
la source
7
Comment se fait-il que vous n'ayez jamais accepté la réponse de SVGreg?
John

Réponses:

79

Oui, lorsque le nombre initial est défini sur 0 - tous les threads seront en attente pendant que vous incrémentez la propriété "CurrentCount". Vous pouvez le faire avec Release () ou Release (Int32).

Release (...) - incrémentera le compteur de sémaphore

Attendez (...) - le décrémentera

Vous ne pouvez pas incrémenter le compteur (propriété "CurrentCount") supérieur au nombre maximum que vous avez défini lors de l'initialisation.

Par exemple:

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()
SVGreg
la source
1
Votre code sera mieux présenté dans la réponse plutôt que sous forme de commentaire.
ChrisF
14
LOL c'est probablement la 5ème fois que j'arrive à cette même réponse car la documentation du constructeur me confond toujours sur les valeurs à définir. Cheers
BlueStrat
70

Donc, je suis vraiment confus sur la signification du décompte initial?

Un point important qui peut aider ici est qu'il Waitdécrémente le nombre de sémaphores et l' Releaseincrémente.

initialCountest le nombre d'accès aux ressources qui seront autorisés immédiatement. Ou, en d'autres termes, c'est le nombre de fois que l' Waiton peut appeler sans blocage immédiatement après l'instanciation du sémaphore.

maximumCountest le nombre le plus élevé que le sémaphore puisse obtenir. C'est le nombre de fois que l' Releaseon peut appeler sans lever d'exception en supposant que le initialCountcompte était nul. Si initialCountest défini sur la même valeur que maximumCountpuis appeler Releaseimmédiatement après que le sémaphore a été instancié lèvera une exception.

Brian Gideon
la source
20
C'est tellement utile! J'avais pensé aux sémaphores à l'envers, car dans initialCount étant le nombre de ressources BLOQUÉES initiales, pas le nombre de ressources disponibles immédiatement. Merci.
Philip Tenn
5
@PhilipTenn, je suis d'accord - la documentation n'est pas claire à ce sujet
BlueStrat
J'ai accepté, ils devraient changer ce nom de variable ou mettre à jour la documentation
IronHide
@Sandbox vous devriez accepter cette réponse IMO, car elle explique vraiment la signification du initialCountparamètre.
Michał Turczyn
8

Combien de threads voulez-vous pouvoir accéder aux ressources à la fois? Réglez votre décompte initial sur ce nombre. Si ce nombre ne va jamais augmenter tout au long de la vie du programme, définissez également votre nombre maximum sur ce nombre. De cette façon, si vous rencontrez une erreur de programmation dans la façon dont vous libérez la ressource, votre programme plantera et vous en informera.

(Il existe deux constructeurs: un qui ne prend qu'une valeur initiale et un qui prend en plus le nombre maximal. Utilisez celui qui est approprié.)

Karmastan
la source
1

De cette façon, lorsque le thread actuel crée le sémaphore, il peut réclamer des ressources dès le début.

Euh non
la source
Donc, vous voulez dire que lorsque je veux que deux threads de travail accèdent à la ressource, je dois changer le nombre initial?
Sandbox
Non. C'est le thread actuel qui revendique un décompte. Si vous ne souhaitez pas que le thread actuel revendique une passe d'accès 0 ou utilise la surcharge avec un paramètre.
Erno
1

Si vous souhaitez qu'aucun thread n'accède à votre ressource pendant un certain temps, vous passez le décompte initial à 0 et lorsque vous souhaitez leur accorder l'accès à tous juste après la création du sémaphore, vous passez la valeur du décompte initial égale au décompte maximum . Par exemple:

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

Comme indiqué dans la documentation MSDN: "Une autre utilisation de ReleaseSemaphore est lors de l'initialisation d'une application. L'application peut créer un sémaphore avec un nombre initial de zéro. Cela définit l'état du sémaphore sur non signal et empêche tous les threads d'accéder à la ressource protégée. termine son initialisation, il utilise ReleaseSemaphore pour augmenter le nombre à sa valeur maximale, pour permettre un accès normal à la ressource protégée. "

Abhineet
la source
Désolé, je vous ai donné l'exemple en C ++ mais peut dissiper le doute.
Abhineet
0

Les sémaphores peuvent être utilisés pour protéger un pool de ressources . Nous utilisons des pools de ressources pour réutiliser des éléments coûteux à créer , tels que les connexions aux bases de données.

Ainsi, le décompte initial fait référence au nombre de ressources disponibles dans le pool au début d'un processus. Lorsque vous lisez le initialCountcode, vous devriez penser à l'effort initial que vous déployez pour créer ce pool de ressources.

Je suis vraiment confus sur la signification du décompte initial?

Initial count = Upfront cost

En tant que tel, selon le profil d'utilisation de votre application, cette valeur peut avoir un effet dramatique sur les performances de votre application. Ce n'est pas seulement un nombre arbitraire.

Vous devez réfléchir attentivement à ce que vous créez, à leur coût de création et au nombre dont vous avez besoin tout de suite. Vous devriez littéralement être capable de représenter graphiquement la valeur optimale de ce paramètre et probablement penser à le rendre configurable afin que vous puissiez adapter les performances du processus au moment où il est exécuté.

rism
la source
-1

Comme MSDN l' explique dans la section Remarques:

Si initialCount est inférieur à maximumCount, l'effet est le même que si le thread actuel avait appelé WaitOne (maximumCount moins initialCount) fois. Si vous ne souhaitez réserver aucune entrée pour le thread qui crée le sémaphore, utilisez le même nombre pour maximumCount et initialCount.

Donc, si le nombre initial est 0 et max est 2, c'est comme si WaitOne avait été appelé deux fois par le thread principal, donc nous avons atteint la capacité (le nombre de sémaphores est 0 maintenant) et aucun thread ne peut entrer dans Semaphore. De même, si le nombre initial est 1 et max est 2 WaitOnce a été appelé une fois et un seul thread peut entrer avant que nous n'atteignions à nouveau la capacité et ainsi de suite.

Si 0 est utilisé pour le compte initial, nous pouvons toujours appeler Release (2) pour augmenter le nombre de sémaphores au maximum afin de permettre au nombre maximum de threads d'acquérir des ressources.

Irfan
la source