Monitor - i programmeringsspråk, en högnivåmekanism för interaktion och synkronisering av processer som ger tillgång till delade resurser. [1] Ett tillvägagångssätt för att synkronisera två eller flera datoruppgifter med hjälp av en gemensam resurs, vanligtvis hårdvara eller en uppsättning variabler .
I monitorbaserad multitasking infogar kompilatorn eller tolken transparent lås-upplåsningskod i lämpligt formaterade rutiner, transparent för programmeraren, vilket sparar programmeraren från att explicit anropa synkroniseringsprimitiver.
Per Brinch Hansen var den första som beskrev och implementerade monitorer, baserade dem på Hoares idéer . Därefter utvecklade Hoare det teoretiska ramverket och visade dess likvärdighet med semaforer (med den ursprungliga semantiken). Första formen i språket Concurrent Pascal och användes för att strukturera kommunikation mellan processer i operativsystemet Solo .
Monitorn består av:
Monitorproceduren skaffar mutex innan arbetet påbörjas och håller den antingen tills proceduren avslutas eller tills ett tillstånd inväntas (se nedan). Om varje procedur garanterar att invarianten är sann innan mutexet släpps, kan ingen uppgift förvärva resursen i ett rastillstånd.
Ett enkelt exempel. Överväg en monitor som utför bankkontotransaktioner.
övervaka konto { int saldo := 0 function draw( int summa) { om belopp < 0 då felet "Kontot kan inte vara negativt" annars om saldo < belopp sedan fel "Brist på pengar" annars saldo := saldo - belopp } function deposit( int summa) { om belopp < 0 då felet "Beloppet kan inte vara negativt" annars saldo := saldo + belopp } }Invarianten här anger helt enkelt att saldot måste återspegla alla tidigare transaktioner innan en ny transaktion börjar. Detta uttrycks vanligtvis inte i kod, men är underförstått och kan nämnas i kommentarer . Det finns dock programmeringsspråk som Eiffel eller D som kan leta efter invarianter. Låset läggs till av kompilatorn. Detta gör monitorer säkrare och mer bekväma än andra metoder som kräver att programmeraren manuellt lägger till lås-upplåsningsoperationer eftersom programmeraren kan glömma att lägga till dem.
För att undvika det aktiva väntetillståndet måste processer signalera varandra om förväntade händelser. Monitorer tillhandahåller denna förmåga genom tillståndsvariabler . När en övervakningsprocedur kräver att ett visst villkor är uppfyllt för att fortsätta, väntar den på den associerade villkorsvariabeln. Medan den väntar släpper den mutexen tillfälligt och hoppar av listan över pågående processer. Alla processer som senare gör att detta villkor uppfylls använder villkorsvariabeln för att meddela vänteprocessen. Den anmälda processen återhämtar mutex och kan fortsätta.
Följande monitor använder villkorsvariabler för att implementera en kanal mellan processer som endast kan lagra ett heltalsvärde åt gången.
monitor channel { int contents boolean full := falskt tillstånd snd condition rcv function send( int message) { while full do wait(rcv) // Mesa semantik: se nedan innehåll := meddelande full := sant meddela (snd) } function receive() { var int mottagen medan den inte är full gör wait(snd) // Mesa semantik: se nedan mottagen := innehåll full := falsk meddela (rcv) retur mottagen } }Observera att eftersom väntan på ett villkor släpper låset, måste vänteprocessen säkerställa att invarianten uppfylls innan du börjar vänta. I exemplet ovan gäller samma sak för varningen.
I tidiga monitorimplementeringar (känd som Hoare -semantik ), väcker meddelande av en villkorsvariabel omedelbart vänteprocessen och återställer låset, vilket säkerställer att villkoret fortfarande är sant.
Att implementera detta beteende är komplext och mycket överflödigt. Det är inte heller kompatibelt med förebyggande multitasking , där processen kan avbrytas vid ett godtyckligt ögonblick. Av dessa skäl har forskare utvecklat många andra semantiker för tillståndsvariabler.
I de mest moderna implementeringarna (kända som Mesa semantik ) avbryter inte meddelandet en pågående process, utan sätter helt enkelt vissa väntande processer i ett klart tillstånd. Meddelandeprocessen fortsätter att hålla låset tills det lämnar övervakningsproceduren. Bieffekterna av detta tillvägagångssätt är att meddelandeprocessen inte krävs för att observera pre-notifieringsinvarianten, utan vänteprocessen måste kontrollera om tillståndet den väntar på. I synnerhet, om övervakningsproceduren innehåller ett uttryck , kan en annan process komma in i monitorn efter meddelandeögonblicket och ändra värdet innan vänteprocessen återupptas. Uttrycket ska skrivas om så här: så att villkoret kontrolleras igen efter väntan. if test then wait(cv)testwhile test do wait(cv)
Implementeringar tillhandahåller också en "notifyAll"- eller "broadcast"-operation som meddelar alla processer som väntar på ett givet tillstånd. Denna operation är användbar, till exempel när flera processer väntar på att olika mängder minne ska vara tillgängligt. Att frigöra minne gör att en av dem kan fortsätta arbeta, men schemaläggaren kan inte veta vilken.
Ett exempel på implementering av en villkorsvariabel:
conditionVariable { int queueSize = 0; mutex lås; semafor väntar; vänta() { lock.acquire(); queueSize++; lock.release(); waiting.down(); } signal() { lock.acquire(); while (köstorlek > 0){ queueSize--; waiting.up(); } lock.release(); } }Programmeringsspråk som stöder monitorer: