Semafor - jaki jest pożytek z liczenia początkowego?

91

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

Aby utworzyć semafor, muszę podać liczbę początkową i maksymalną. MSDN stwierdza, że ​​początkowa liczba to -

Początkowa liczba żądań semafora, które mogą być przyznane jednocześnie.

Chociaż stwierdza, że ​​maksymalna liczba to

Maksymalna liczba żądań semafora, które mogą być przyznane jednocześnie.

Rozumiem, że maksymalna liczba to maksymalna liczba wątków, które mogą jednocześnie uzyskać dostęp do zasobu. Ale jaki jest pożytek z liczenia początkowego?

Jeśli utworzę semafor z początkową liczbą 0 i maksymalną liczbą 2, żaden z moich wątków wątków nie będzie mógł uzyskać dostępu do zasobu. Jeśli ustawię początkową liczbę na 1 i maksymalną liczbę na 2, tylko wątek puli wątków będzie miał dostęp do zasobu. To jest tylko wtedy, gdy ustawię zarówno początkową liczbę, jak i maksymalną liczbę na 2, 2 wątki mogą jednocześnie uzyskać dostęp do zasobu. Więc jestem naprawdę zdezorientowany co do znaczenia początkowej liczby?

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
Piaskownica
źródło
7
Dlaczego nigdy nie zaakceptowałeś odpowiedzi SVGreg?
John

Odpowiedzi:

79

Tak, gdy początkowa liczba jest ustawiona na 0 - wszystkie wątki będą czekać podczas zwiększania właściwości „CurrentCount”. Możesz to zrobić za pomocą Release () lub Release (Int32).

Release (...) - zwiększy licznik semaforów

Czekaj (...) - zmniejszy to

Nie można zwiększyć licznika (właściwość „CurrentCount”) powyżej maksymalnej liczby ustawionej podczas inicjalizacji.

Na przykład:

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
źródło
1
Twój kod będzie lepiej przedstawiony w odpowiedzi niż jako komentarz.
ChrisF
14
LOL, to chyba piąty raz, kiedy dochodzę do tej samej odpowiedzi, ponieważ dokumentacja konstruktora zawsze myli mnie, które wartości ustawić. Pozdrawiam
BlueStrat
70

Więc jestem naprawdę zdezorientowany co do znaczenia początkowej liczby?

Jedna ważna kwestia, która może tutaj pomóc, jest taka Wait zmniejszenie liczby semaforów i Releasezwiększenie jej.

initialCountto liczba dostępów do zasobów, które będą natychmiast dozwolone. Innymi słowy, jest to liczba wywołań, które Waitmożna wywołać bez blokowania bezpośrednio po utworzeniu wystąpienia semafora.

maximumCountjest największą liczbą, jaką może uzyskać semafor. Jest to liczba wywołań, które Releasemożna wywołać bez zgłaszania wyjątku, zakładając, że initialCountliczba wynosi zero. Jeśli initialCountjest ustawiona na taką samą wartość, jak maximumCountwtedy, wywołanie Releasenatychmiast po utworzeniu wystąpienia semafora spowoduje zgłoszenie wyjątku.

Brian Gideon
źródło
20
To jest bardzo pomocne! Myślałem o Semaforach wstecz, ponieważ w initialCount była to liczba początkowych ZABLOKOWANYCH zasobów, a nie liczba zasobów, które są dostępne natychmiast. Dziękuję Ci.
Philip Tenn
5
@PhilipTenn, zgadzam się - dokumentacja nie jest jasna w tym zakresie
BlueStrat
Zgodziłem się, powinni zmienić nazwę tej zmiennej lub zaktualizować dokumenty
IronHide,
@Sandbox powinieneś zaakceptować tę odpowiedź IMO, ponieważ naprawdę wyjaśnia znaczenie initialCountparametru.
Michał Turczyn
8

Ile wątków chcesz mieć jednocześnie dostęp do zasobów? Ustaw początkową liczbę na tę liczbę. Jeśli ta liczba nigdy nie wzrośnie przez cały czas trwania programu, ustaw maksymalną liczbę również na tę liczbę. W ten sposób, jeśli wystąpi błąd programowania dotyczący sposobu zwalniania zasobu, program ulegnie awarii i poinformuje Cię o tym.

(Istnieją dwa konstruktory: jeden, który przyjmuje tylko wartość początkową, i drugi, który dodatkowo przyjmuje maksymalną liczbę. Użyj tego, który jest odpowiedni).

Karmastan
źródło
1

W ten sposób, gdy bieżący wątek tworzy semafor, może zażądać pewnych zasobów od początku.

Eee nie
źródło
Więc masz na myśli, że kiedy chcę, aby dwa wątki robocze miały dostęp do zasobu, powinienem zmienić początkową liczbę?
Piaskownica
Nie. To bieżący wątek, który podaje liczbę. Jeśli nie chcesz, aby bieżący wątek żądał dowolnego przejścia dostępu 0 lub użyj przeciążenia z jednym parametrem.
Erno,
1

Jeśli chcesz, aby żaden wątek nie miał dostępu do twojego zasobu przez jakiś czas, przekazujesz początkową liczbę jako 0, a gdy chcesz udzielić dostępu wszystkim z nich zaraz po utworzeniu semafora, przekazujesz wartość początkowego licznika równą maksymalnej liczbie . Na przykład:

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

Jak podano w dokumentacji MSDN - „Innym zastosowaniem ReleaseSemaphore jest inicjalizacja aplikacji. Aplikacja może utworzyć semafor z początkową liczbą zerową. To ustawia stan semafora na niesygnalizowany i blokuje dostęp wszystkich wątków do chronionego zasobu. Gdy aplikacja kończy inicjalizację, używa ReleaseSemaphore w celu zwiększenia liczby do wartości maksymalnej, aby umożliwić normalny dostęp do chronionego zasobu. "

Abhineet
źródło
Przepraszam, podałem przykład w C ++, ale może rozwiać wątpliwości.
Abhineet
0

Semafory mogą służyć do ochrony puli zasobów . Używamy pul zasobów do ponownego wykorzystania rzeczy, których tworzenie jest drogie - takich jak połączenia z bazami danych.

Zatem początkowa liczba odnosi się do liczby dostępnych zasobów w puli na początku jakiegoś procesu. Czytając initialCountkod, powinieneś pomyśleć o tym, ile wysiłku wkładasz z góry w tworzenie tej puli zasobów.

Jestem naprawdę zdezorientowany co do znaczenia początkowego liczenia?

Initial count = Upfront cost

W związku z tym, w zależności od profilu użytkowania aplikacji, wartość ta może mieć dramatyczny wpływ na wydajność aplikacji. To nie jest dowolna liczba.

Powinieneś dokładnie przemyśleć, co tworzysz, jak drogie są one w tworzeniu i ile potrzebujesz od razu. Powinieneś być w stanie dosłownie być w stanie wykreślić optymalną wartość tego parametru i prawdopodobnie powinieneś pomyśleć o skonfigurowaniu go, abyś mógł dostosować wydajność procesu do czasu, w którym jest wykonywany.

ryzm
źródło
-1

Jak wyjaśnia MSDN w sekcji Uwagi:

Jeśli initialCount jest mniejsze niż maximumCount, efekt jest taki sam, jak gdyby bieżący wątek wywołał WaitOne (maximumCount minus initialCount) razy. Jeśli nie chcesz rezerwować żadnych wpisów dla wątku, który tworzy semafor, użyj tej samej liczby dla maximumCount i initialCount.

Więc jeśli początkowa liczba to 0, a max to 2, to tak, jakby WaitOne został wywołany dwukrotnie przez główny wątek, więc osiągnęliśmy pojemność (liczba semaforów wynosi teraz 0) i żaden wątek nie może wejść do Semafora. Podobnie, jeśli początkowa liczba to 1, a maksymalna to 2, WaitOnce został wywołany raz i tylko jeden wątek może wejść, zanim ponownie osiągniemy pojemność i tak dalej.

Jeśli do zliczania początkowego użyto 0, zawsze możemy wywołać Release (2), aby zwiększyć liczbę semaforów do maks., Aby umożliwić maksymalną liczbę wątków w celu uzyskania zasobu.

Irfan
źródło