Dela via


Semaforobjekt

Alla drivrutiner kan använda ett semaforobjekt för att synkronisera åtgärder mellan sina drivrutinsskapade trådar och andra drivrutinsrutiner. En drivrutinsdedikerad tråd kan till exempel försätta sig själv i väntetillstånd när det inte finns några utestående I/O-begäranden för drivrutinen, och drivrutinens sändningsrutiner kan ställa in semaforen till tillståndet Signaled strax efter att de har köat en IRP.

Sändningsrutinerna för drivrutiner på högsta nivå, som körs i kontexten för tråden som begär en I/O-åtgärd, kan använda en semafor för att skydda en resurs som delas mellan sändningsrutinerna. Rutiner för att skicka drivrutiner på lägre nivå för synkrona I/O-åtgärder kan också använda en semafor för att skydda en resurs som delas mellan den delmängden av sändningsrutiner eller med en drivrutinsskapad tråd.

Alla drivrutiner som använder ett semaforobjekt måste anropa KeInitializeSemaphore innan det väntar eller släpper semaforen. Följande bild visar hur en drivrutin med en tråd kan använda ett semaforobjekt.

diagram som illustrerar väntan på ett semaforobjekt.

Som föregående bild visar måste en sådan drivrutin tillhandahålla lagringen för semaforobjektet, som ska vara bosatt. Drivrutinen kan använda enhetstillägget för ett enhetsobjekt som skapats av drivrutinen, kontrollanttillägget om det använder ett kontrollantobjekteller en pool som inte har allokerats av drivrutinen.

När förarens AddDevice rutinanrop KeInitializeSemaphoremåste den skicka en pekare till förarens lagringsplats för semaforobjektet. Dessutom måste anroparen ange ett Antal för semaforobjektet, som visas i föregående bild, som bestämmer dess ursprungliga tillstånd (nonzero för Signaled).

Anroparen måste också ange en Gräns för semaforen, vilket kan vara något av följande:

  • Gräns = 1

    När den här semaforen är inställd på signaltillståndet blir en enda tråd som väntar på att semaforen ska ställas in på det signalerade tillståndet berättigad till körning och kan komma åt den resurs som skyddas av semaforen.

    Den här typen av semafor kallas också för en binär semafor eftersom en tråd antingen har eller inte har exklusiv åtkomst till den semaforskyddade resursen.

  • Gräns > 1

    När den här semaforen är inställd på signaltillståndet blir ett antal trådar som väntar på att semaforobjektet ska ställas in på det signalerade tillståndet berättigat till körning och kan komma åt den resurs som skyddas av semaforen.

    Denna typ av semafor kallas en räkna semafor eftersom rutinen som anger semaforen till det signalerade tillståndet också anger hur många väntande trådar som kan få sina tillstånd ändrade från att vänta till redo. Antalet sådana väntande trådar kan vara Gräns anges när semaforen initierades eller något tal mindre än den här förinställningen Limit.

Få enhetsdrivrutiner eller mellanliggande drivrutiner har en enda drivrutinsskapad tråd. ännu färre har en uppsättning trådar som kan vänta på att en semafor förvärvas eller frigörs. Få drivrutiner som tillhandahålls av systemet använder semaforobjekt, och av dem som gör det använder ännu färre en binär semafor. Även om en binär semafor kan tyckas likna en mutex-objektger en binär semafor inte det inbyggda skyddet mot dödlägen som ett mutex-objekt har för systemtrådar som körs på SMP-datorer.

När en drivrutin med en initierad semafor har lästs in kan den synkronisera åtgärder på semaforen som skyddar en delad resurs. Till exempel kan en drivrutin med en enhetsdedikerad tråd som hanterar köer för IP-adresser, till exempel drivrutinen för systemdiskettkontrollanten, synkronisera IRP-köer på en semafor, som du ser i föregående bild:

  1. Tråden anropar KeWaitForSingleObject med en pekare till drivrutinslagringen för det initierade semaforobjektet för att försätta sig själv i väntetillstånd.

  2. IRP:er börjar komma in som kräver enhets-I/O-åtgärder. Förarens sändningsrutiner infogar varje sådan IRP i en sammanflätad kö under spin-lock-kontroll och anropar KeReleaseSemaphore med en pekare till semaforobjektet, en drivrutinsbestämd prioritetsökning för tråden (Öka, som du ser i föregående bild), en Justering av 1 som läggs till i semaforens antal när varje IRP placeras i kö, och en boolesk Vänta inställd på FALSE. En nonzero semaphore Count anger semaforobjektet till det signalerade tillståndet, vilket ändrar den väntande trådens tillstånd till redo.

  3. Kerneln skickar tråden för körning så snart en processor är tillgänglig: det vill säga ingen annan tråd med högre prioritet är för närvarande i redo tillstånd och det finns inga kernel-läge rutiner som ska köras på en högre IRQL.

    Tråden tar bort en IRP från den sammankopplade kön under spin-lock-kontroll, skickar den vidare till andra drivrutinsrutiner för vidare bearbetning och anropar KeWaitForSingleObject igen. Om semaforen fortfarande är inställd på tillståndet Signaled (det vill säga att antalet förblir icke-noll, vilket indikerar att fler IP-adresser finns i drivrutinens sammankopplade kö), ändrar kerneln återigen trådens tillstånd från att vänta till redo.

    Genom att använda en räknande semafor på det här sättet vet en sådan drivrutinstråd att det finns en IRP som ska tas bort från den sammankopplade kön när tråden körs.

Information som är specifik för att hantera IRQL när du anropar KeReleaseSemaphorefinns i avsnittet Anmärkningar i KeReleaseSemaphore.

Alla standarddrivrutiner som körs vid en IRQL som är större än PASSIVE_LEVEL kan inte vänta på ett icke-nollintervall på några dispatcher-objekt utan att ta ner systemet. Mer information finns i Kernel Dispatcher-objekt. En sådan rutin kan dock anropa KeReleaseSemaphore när den körs på en IRQL som är mindre än eller lika med DISPATCH_LEVEL.

En sammanfattning av de IRQL:er där standarddrivrutinsrutiner körs finns i Hantera maskinvaruprioriteringar. Information om IRQL-krav för en specifik supportrutin finns på rutinens referenssida.