Delen via


Semaphore en SemaphoreSlim

De System.Threading.Semaphore klasse vertegenwoordigt een benoemde (systeemomvattende) of lokale semafore. Het is een dunne wrapper rond het Win32-semaphore-object. Win32-semaforen zijn tellende semaforen die de toegang tot een bronpool beheren.

De SemaphoreSlim klasse vertegenwoordigt een lichtgewicht, snelle semafoor die kan worden gebruikt voor het wachten binnen één proces wanneer verwacht wordt dat de wachttijden kort zijn. Tijdens de spin-wachtfase is de CPU actief bezig; het is niet inactief. Hoe kort 'kort' moet zijn, hangt af van de aard van de wachttijd: als threads concurreren voor CPU-resources, verbruikt de draaiende thread CPU-tijd, dus de wachttijd moet erg kort zijn, gemeten in microseconden. Als de wachttijd voor een niet-CPU-afhankelijke resource (zoals I/O) is, is de overhead voor spin-wait minder van belang en kan de acceptabele wachttijd iets langer zijn, gemeten in milliseconden. Wanneer wachttijden onvoorspelbaar zijn of naar verwachting significant, gebruik in plaats daarvan System.Threading.Semaphore, dat niet draait. SemaphoreSlim is zoveel mogelijk afhankelijk van synchronisatie primitiefen die worden geleverd door de Common Language Runtime (CLR). Het biedt echter ook vertraagd geïnitialiseerde wachtgrepen op basis van kernel indien nodig ter ondersteuning van het wachten op meerdere semaphores. SemaphoreSlim ondersteunt ook het gebruik van annuleringstokens, maar biedt geen ondersteuning voor benoemde semaforen of het gebruik van een wachtgreep voor synchronisatie.

Een beperkte resource beheren

Threads voeren semaforen binnen door verschillende methoden aan te roepen, afhankelijk van het type semaforen. Roep voor een System.Threading.Semaphore object de WaitOne methode aan (overgenomen van WaitHandle). Roep voor een SemaphoreSlim object de SemaphoreSlim.Wait of SemaphoreSlim.WaitAsync methode aan. Wanneer de aanroep terugkeert, wordt de telling van de semafoor verminderd. Wanneer een thread invoer aanvraagt en het aantal nul is, blokkeert de thread. Als threads de semaphore vrijgeven door de Semaphore.Release of SemaphoreSlim.Release methode aan te roepen, kunnen geblokkeerde threads binnenkomen. Geen gegarandeerde volgorde, zoals first-in, first-out (FIFO) of last-in, first-out (LIFO), bepaalt welke geblokkeerde thread de volgende semaphore binnenkomt.

Een thread kan meerdere keren de semafoor invoeren door herhaaldelijk de System.Threading.Semaphore-methode van het WaitOne-object of de SemaphoreSlim-methode van het Wait-object aan te roepen. Als u de semafoor wilt vrijgeven, roept u de Semaphore.Release() of SemaphoreSlim.Release() methode hetzelfde aantal keren aan dat de thread is binnengekomen. U kunt ook de Semaphore.Release(Int32) of SemaphoreSlim.Release(Int32) overbelasting aanroepen en het aantal vermeldingen opgeven dat moet worden vrijgegeven.

Semaphores en threadidentiteit

De twee semaforen typen dwingen geen thread-identiteit af bij aanroepen van de WaitOne, Wait, Release en SemaphoreSlim.Release-methoden. Een gebruikelijk gebruiksscenario voor semaphores omvat bijvoorbeeld een producentthread en een consumententhread, waarbij één thread altijd de semaphorewaarde verhoogt en de andere deze altijd decrementeert.

Zorg ervoor dat een thread de semaphore niet te vaak loslaat. Stel dat een semaphore een maximumaantal van twee heeft en dat thread A en thread B beide de semaphore binnenkomen. Als een programmeerfout in thread B ervoor zorgt dat Release twee keer wordt aangeroepen, slagen beide aanroepen. Het aantal op de semaphore is vol, en wanneer thread A Release aanroept, uiteindelijk wordt er een SemaphoreFullException gegenereerd.

Benoemde semaforen

Met het Windows-besturingssysteem kunnen semaforen namen hebben. Een benoemde semaphore is systeembreed, zodra deze is gemaakt, is deze zichtbaar voor alle threads in alle processen. Benoemde semaphores kunnen daarom de activiteiten van processen en threads synchroniseren.

Maak een Semaphore object dat een benoemd systeemsemafore vertegenwoordigt met behulp van een van de constructors die een naam specificeert.

Belangrijk

Omdat benoemde semaphores systeembreed zijn, is het mogelijk om meerdere Semaphore objecten te hebben die dezelfde benoemde semafore vertegenwoordigen. Telkens wanneer u een constructor of methode Semaphore.OpenExisting aanroept, wordt er een nieuw Semaphore object gemaakt. Als u dezelfde naam opgeeft, worden meerdere objecten gemaakt die dezelfde benoemde semaphore vertegenwoordigen.

Wees voorzichtig wanneer u benoemde semaforen gebruikt. Omdat ze systeembreed zijn, kan een ander proces dat dezelfde naam gebruikt, uw semafoor onverwacht benaderen. Schadelijke code die op dezelfde computer wordt uitgevoerd, kan dit gebruiken als basis van een denial-of-service-aanval.

Gebruik de beveiliging van toegangsbeheer om een Semaphore object te beveiligen dat een benoemde semafore vertegenwoordigt, bij voorkeur met behulp van een constructor die een System.Security.AccessControl.SemaphoreSecurity object opgeeft. U kunt ook de beveiliging van toegangsbeheer toepassen met behulp van de Semaphore.SetAccessControl methode, maar dit laat een beveiligingsvenster achter tussen de tijd dat de semafor wordt gemaakt en het tijdstip waarop deze is beveiligd. Het beveiligen van semaphores met beveiliging van toegangsbeheer helpt schadelijke aanvallen te voorkomen, maar lost het probleem van onbedoelde naamconflicten niet op.

Zie ook