Semaphor - Wozu dient die Anfangszählung?


89

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

Um ein Semaphor zu erstellen, muss ich eine anfängliche und eine maximale Anzahl angeben. MSDN gibt an, dass eine anfängliche Zählung - ist

Die anfängliche Anzahl von Anforderungen für das Semaphor, die gleichzeitig gewährt werden können.

Während es angibt, dass die maximale Anzahl ist

Die maximale Anzahl von Anforderungen für das Semaphor, die gleichzeitig gewährt werden können.

Ich kann verstehen, dass die maximale Anzahl die maximale Anzahl von Threads ist, die gleichzeitig auf eine Ressource zugreifen können. Aber was nützt die anfängliche Zählung?

Wenn ich ein Semaphor mit einer anfänglichen Anzahl von 0 und einer maximalen Anzahl von 2 erstelle, kann keiner meiner Threadpool-Threads auf die Ressource zugreifen. Wenn ich die anfängliche Anzahl auf 1 und die maximale Anzahl auf 2 setze, kann nur der Thread-Pool-Thread auf die Ressource zugreifen. Nur wenn ich sowohl die anfängliche als auch die maximale Anzahl auf 2 festgelegt habe, können 2 Threads gleichzeitig auf die Ressource zugreifen. Also bin ich wirklich verwirrt über die Bedeutung der anfänglichen Zählung?

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

5
Wieso hast du die Antwort von SVGreg nie akzeptiert?
John

Antworten:


78

Ja, wenn die Anfangsnummer auf 0 gesetzt ist, warten alle Threads, während Sie die Eigenschaft "CurrentCount" erhöhen. Sie können dies mit Release () oder Release (Int32) tun.

Release (...) - erhöht den Semaphorzähler

Warten Sie (...) - wird es dekrementieren

Sie können den Zähler ("CurrentCount" -Eigenschaft) nicht größer als die maximale Anzahl erhöhen, die Sie bei der Initialisierung festgelegt haben.

Beispielsweise:

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
Ihr Code wird in der Antwort besser dargestellt als als Kommentar.
ChrisF

13
LOL Es ist wahrscheinlich das fünfte Mal, dass ich dieselbe Antwort erreiche, da mich die Dokumentation des Konstruktors immer verwirrt, welche Werte eingestellt werden sollen. Prost
BlueStrat

63

Also bin ich wirklich verwirrt über die Bedeutung der anfänglichen Zählung?

Ein wichtiger Punkt, der hier hilfreich sein kann, ist, dass Waitdie Anzahl der Semaphore verringert und Releaseerhöht wird.

initialCountist die Anzahl der Ressourcenzugriffe, die sofort zulässig sind. Mit anderen Worten, es ist die WaitHäufigkeit, mit der unmittelbar nach der Instanziierung des Semaphors aufgerufen werden kann, ohne zu blockieren.

maximumCountist die höchste Anzahl, die das Semaphor erhalten kann. Es ist die Häufigkeit, mit der Releaseaufgerufen werden kann, ohne eine Ausnahme auszulösen, vorausgesetzt, die initialCountAnzahl war Null. Wenn initialCountderselbe Wert wie beim maximumCountAufrufen Releaseunmittelbar nach der Instanziierung des Semaphors festgelegt ist, wird eine Ausnahme ausgelöst.


18
Das ist so hilfreich! Ich hatte rückwärts über Semaphore nachgedacht, da in initialCount die Anzahl der anfänglichen BLOCKED-Ressourcen und nicht die Anzahl der Ressourcen, die sofort verfügbar sind. Danke dir.
Philip Tenn

5
@PhilipTenn, ich stimme zu - die Dokumentation ist in dieser Hinsicht nicht klar
BlueStrat

Ich stimmte zu, sie sollten diesen Variablennamen ändern oder die Dokumente aktualisieren
IronHide

@ Sandbox Sie sollten diese Antwort IMO akzeptieren, da sie die Bedeutung von initialCountParametern wirklich erklärt .
Michał Turczyn

8

Wie viele Threads möchten Sie gleichzeitig auf Ressourcen zugreifen können? Stellen Sie Ihre anfängliche Anzahl auf diese Zahl ein. Wenn sich diese Zahl während der gesamten Laufzeit des Programms nie erhöht, setzen Sie auch Ihre maximale Anzahl auf diese Zahl. Auf diese Weise stürzt Ihr Programm ab und informiert Sie, wenn Sie einen Programmierfehler bei der Freigabe der Ressource haben.

(Es gibt zwei Konstruktoren: einen, der nur einen Anfangswert annimmt, und einen, der zusätzlich die maximale Anzahl annimmt. Verwenden Sie den geeigneten.)


1

Auf diese Weise kann der aktuelle Thread beim Erstellen des Semaphors von Anfang an einige Ressourcen beanspruchen.


Sie meinen also, wenn zwei Arbeitsthreads auf die Ressource zugreifen sollen, sollte ich die anfängliche Anzahl ändern?
Sandbox

Nein. Es ist der aktuelle Thread, der eine Zählung beansprucht. Wenn Sie nicht möchten, dass der aktuelle Thread einen Zugriffsdurchlauf 0 beansprucht, oder die Überladung mit einem Parameter verwenden.
Erno

1

Wenn Sie möchten, dass für einige Zeit kein Thread auf Ihre Ressource zugreift, übergeben Sie die anfängliche Anzahl als 0, und wenn Sie allen nach dem Erstellen des Semaphors den Zugriff gewähren möchten, übergeben Sie den Wert der anfänglichen Anzahl gleich der maximalen Anzahl . Beispielsweise:

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

Wie in der MSDN-Dokumentation angegeben: "Eine andere Verwendung von ReleaseSemaphore erfolgt während der Initialisierung einer Anwendung. Die Anwendung kann ein Semaphor mit einer Anfangszahl von Null erstellen. Dadurch wird der Status des Semaphors auf nicht signalisiert gesetzt und alle Threads können nicht auf die geschützte Ressource zugreifen. Wenn die Anwendung." Nach Abschluss der Initialisierung wird ReleaseSemaphore verwendet, um die Anzahl auf den Maximalwert zu erhöhen und einen normalen Zugriff auf die geschützte Ressource zu ermöglichen. "


Entschuldigung, ich habe Ihnen das Beispiel in C ++ gegeben, kann aber den Zweifel klären.
Abhineet

0

Semaphoren können verwendet werden, um einen Ressourcenpool zu schützen . Wir verwenden Ressourcenpools, um Dinge wiederzuverwenden , deren Erstellung teuer ist - wie z. B. Datenbankverbindungen.

Die anfängliche Zählung bezieht sich also auf die Anzahl der verfügbaren Ressourcen im Pool zu Beginn eines Prozesses. Wenn Sie den initialCountIn-Code lesen , sollten Sie sich überlegen, wie viel Aufwand Sie im Voraus in die Erstellung dieses Ressourcenpools investieren.

Ich bin wirklich verwirrt über die Bedeutung der anfänglichen Zählung?

Initial count = Upfront cost

Abhängig vom Nutzungsprofil Ihrer Anwendung kann sich dieser Wert dramatisch auf die Leistung Ihrer Anwendung auswirken. Es ist nicht nur eine beliebige Zahl.

Sie sollten sorgfältig überlegen, was Sie erstellen, wie teuer die Erstellung ist und wie viele Sie sofort benötigen. Sie sollten buchstäblich in der Lage sein, den optimalen Wert für diesen Parameter grafisch darzustellen, und sollten wahrscheinlich darüber nachdenken, ihn konfigurierbar zu machen, damit Sie die Leistung des Prozesses an den Zeitpunkt anpassen können, zu dem er ausgeführt wird.


-1

Wie MSDN im Abschnitt "Bemerkungen" erklärt:

Wenn initialCount kleiner als maximumCount ist, ist der Effekt der gleiche, als hätte der aktuelle Thread WaitOne-Zeiten (maximalCount minus initialCount) aufgerufen. Wenn Sie keine Einträge für den Thread reservieren möchten, der das Semaphor erstellt, verwenden Sie dieselbe Nummer für MaximumCount und InitialCount.

Wenn also die anfängliche Anzahl 0 und die maximale Anzahl 2 ist, ist es so, als ob WaitOne vom Hauptthread zweimal aufgerufen wurde, sodass wir die Kapazität erreicht haben (die Semaphoranzahl ist jetzt 0) und kein Thread in Semaphore eintreten kann. Ähnlich Wenn die anfängliche Anzahl 1 und die maximale Anzahl 2 ist, wurde WaitOnce einmal aufgerufen und nur ein Thread kann eintreten, bevor wir wieder die Kapazität erreichen und so weiter.

Wenn 0 für die anfängliche Zählung verwendet wird, können wir immer Release (2) aufrufen, um die Semaphoranzahl auf max zu erhöhen, damit die maximale Anzahl von Threads Ressourcen erfassen kann.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.