Semaforit ovat vain normaaleja muuttujia, joita käytetään koordinoimaan useiden prosessien toimintaa tietokonejärjestelmässä. Niitä käytetään pakottamaan vastavuoroinen poissulkeminen, välttämään kilpailuolosuhteet ja toteuttamaan synkronointi prosessien välillä.
Semaforien käyttöprosessi tarjoaa kaksi toimintoa: odotus (P) ja signaali (V). Odotustoiminto vähentää semaforin arvoa ja signaalitoiminto lisää semaforin arvoa. Kun semaforin arvo on nolla, kaikki odotustoiminnon suorittavat prosessit estetään, kunnes toinen prosessi suorittaa signaalitoiminnon.
Semaforeja käytetään kriittisten osien toteuttamiseen, jotka ovat koodin alueita, jotka vain yhden prosessin on suoritettava kerrallaan. Käyttämällä semaforeja prosessit voivat koordinoida pääsyä jaettuihin resursseihin, kuten jaettuun muistiin tai I/O-laitteisiin.
Semafori on erityinen synkronointidata, jota voidaan käyttää vain tiettyjen synkronointiprimitiivien kautta. Kun prosessi suorittaa semaforille odotusoperaation, operaatio tarkistaa, onko semaforin arvo>0. Jos näin on, se vähentää semaforin arvoa ja antaa prosessin jatkaa sen suorittamista; muuten se estää prosessin semaforissa. Signaalioperaatio semaforilla aktivoi semaforiin estyneen prosessin, jos sellainen on, tai lisää semaforin arvoa yhdellä. Tämän semantiikan vuoksi semaforeja kutsutaan myös laskentasemaforeiksi. Semaforin alkuarvo määrittää, kuinka monta prosessia voi ohittaa odotustoiminnon.
Semaforeja on kahta tyyppiä:
- Binäärinen semafori -
Tämä tunnetaan myös mutex-lukona. Sillä voi olla vain kaksi arvoa – 0 ja 1. Sen arvo alustetaan 1:ksi. Sitä käytetään kriittisten osien ongelmien ratkaisuun useilla prosesseilla. - Semaforien laskeminen -
Sen arvo voi vaihdella rajoittamattoman verkkotunnuksen yli. Sitä käytetään hallitsemaan pääsyä resurssiin, jossa on useita esiintymiä.
Katsotaan nyt, kuinka se tekee sen.
Tarkastele ensin kahta operaatiota, joilla voidaan käyttää ja muuttaa semaforimuuttujan arvoa.

mikä on regex java
Muutama seikka P- ja V-toiminnasta:
- P-toimintoa kutsutaan myös odotus-, lepotila- tai alastoiminnoksi, ja V-toimintoa kutsutaan myös signaali-, herätys- tai ylösoperaatioksi.
- Molemmat toiminnot ovat atomisia ja semafori(t) alustetaan aina yhdeksi. Tässä atomi tarkoittaa sitä muuttujaa, jonka lukeminen, muokkaaminen ja päivitys tapahtuu samaan aikaan/hetkellä ilman etukäteisyyttä, eli lukemisen, muokkaamisen ja päivityksen välissä ei suoriteta mitään muuta toimintoa, joka voi muuttaa muuttujaa.
- Kriittistä osaa ympäröivät molemmat toiminnot prosessisynkronoinnin toteuttamiseksi. Katso alla oleva kuva. Prosessin P kriittinen osa on P- ja V-toiminnan välissä.

Katsotaanpa nyt, kuinka se toteuttaa keskinäisen poissulkemisen. Olkoon kaksi prosessia P1 ja P2 ja semafori s alustetaan luvuksi 1. Jos nyt oletetaan, että P1 tulee kriittiseen osaansa, niin semaforin s arvoksi tulee 0. Jos P2 haluaa mennä kriittiseen osaansa, se odottaa kunnes s> 0, tämä voi tapahtua vain, kun P1 lopettaa kriittisen osuutensa ja kutsuu V-operaation semaforilla s.
Tällä tavalla saavutetaan molemminpuolinen poissulkeminen. Katso lisätietoja alla olevasta kuvasta, joka on binaarinen semafori.

Toteutus: Binaariset semaforit
struct semaphore { enum value(0, 1); // q contains all Process Control Blocks (PCBs) // corresponding to processes got blocked // while performing down operation. Queueq; }; P(semafori s) { if (s.arvo == 1) { s.arvo = 0; } else { // lisää prosessi odotusjonoon q.push(P) sleep(); } } V(semafori s) { if (s.q on tyhjä) { s.arvo = 1; } else { // valitse prosessi odotusjonosta Prosessi p = q.front(); // poista prosessi odottamasta sellaisena kuin se on lähetetty // CS:lle q.pop(); herätys(p); } } // Tätä koodia on muokannut Susobhan Akhuli> C #include #include #include struct semaphore{ Queueq; int arvo; }; void P(rakenne semafori s) { if (s.arvo == 1) { s.arvo = 0; } else { s.q.push(P); nukkua(); } } void V(semafori s) { if (s.q on tyhjä) { s.arvo = 1; } else { // Hae prosessi odotusjonosta Prosessi p = q.front(); // Poista prosessi odottamasta q.pop(); herätys(p); } } int main() { printf('Tämä on hemish!!'); // Tämän koodin tarjoaa Himesh Singh Chauhan return 0; } // Tätä koodia on muokannut Susobhan Akhuli> Java import java.util.*; class Semaphore { public enum Value { Zero, One } public Queueq = uusi LinkedList(); public Arvo arvo = Arvo.Yksi; public void P(Semafori s, Prosessi p) { if (s.arvo == Arvo.Yksi) { s.arvo = Arvo.Nolla; } else { // lisää prosessi odottavaan jonoon q.add(p); p.Sleep(); } } public void V(Semafori s) { if (s.q.size() == 0) { s.value = Arvo.Yksi; } else { // valitse prosessi odotusjonosta Prosessi p = q.peek(); // poista prosessi odottamasta, koska se on // lähetetty CS:lle q.remove(); p. Herätys(); } } }> Python 3 from enum import Enum from queue import Queue class Semaphore: class Value(Enum): Zero = 0 One = 1 def __init__(self): self.q = Queue() self.value = Semaphore.Value.One def P(self, s, p): if s.value == Semaphore.Value.One: s.value = Semaphore.Value.Zero else: # add the process to the waiting queue s.q.put(p) p.Sleep() def V(self, s): if s.q.qsize() == 0: s.value = Semaphore.Value.One else: # select a process from waiting queue p = s.q.queue[0] # remove the process from waiting as it has # been sent for CS s.q.get() p.Wakeup()>
C# using System.Collections.Generic; class Semaphore { public enum value { Zero, One } public Queueq = uusi jono(); public void P(Semafori s, Prosessi p) { if (s.arvo == arvo.Yksi) { s.arvo = arvo.Nolla; } else { // lisää prosessi odottavaan jonoon q.Enqueue(p); p.Sleep(); } } public void V(Semafori s) { if (s.q.Count == 0) { s.value = arvo.Yksi; } else { // valitse prosessi odotusjonosta Prosessi p = q.Peek(); // poista prosessi odottamasta, koska se on lähetetty // CS:lle q.Dequeue(); p. Herätys(); } } }> Javascript class Semaphore { constructor() { this.value = 0; // q contains all Process Control Blocks (PCBs) // corresponding to processes got blocked // while performing down operation. this.q = []; } P() { if (this.value == 1) { this.value = 0; } else { // add the process to the waiting queue this.q.push(P); sleep(); } } V() { if (this.q.length == 0) { this.value = 1; } else { // select a process from waiting queue let p = this.q.shift(); // remove the process from waiting as it has been // sent for CS wakeup(p); } } }> Yllä oleva kuvaus koskee binääristä semaforia, joka voi ottaa vain kaksi arvoa 0 ja 1 ja varmistaa molemminpuolisen poissulkemisen. On olemassa toinen semaforityyppi, jota kutsutaan laskentasemaforiksi ja joka voi ottaa arvoja suurempia kuin yksi.
Oletetaan nyt, että on resurssi, jonka esiintymien lukumäärä on 4. Nyt alustetaan S = 4 ja loput ovat samat kuin binäärisemaforissa. Aina kun prosessi haluaa kyseisen resurssin, se kutsuu P:tä tai odottaa funktiota ja kun se on tehty, se kutsuu V tai signaalifunktiota. Jos S:n arvosta tulee nolla, prosessin on odotettava, kunnes S muuttuu positiiviseksi. Oletetaan esimerkiksi, että prosesseja P1, P2, P3, P4 on 4, ja ne kaikki kutsuvat odotustoimintoa S:llä (alustus 4:llä). Jos toinen prosessi P5 haluaa resurssin, sen tulee odottaa kunnes yksi neljästä prosessista kutsuu signaalifunktiota ja semaforin arvo muuttuu positiiviseksi.
Rajoitukset:
- Yksi semaforin suurimmista rajoituksista on prioriteetin inversio.
- Umpikuja, oletetaan, että prosessi yrittää herättää toisen prosessin, joka ei ole lepotilassa. Siksi umpikuja voi lukkiutua määräämättömäksi ajaksi.
- Käyttöjärjestelmän on pidettävä kirjaa kaikista puheluista odottaakseen ja lähettääkseen semaforin signaalin.
Ongelma tässä semaforin toteutuksessa:
Semaforien suurin ongelma on, että ne vaativat kiireistä odottamista. Jos prosessi on kriittisessä osassa, muut kriittiseen osioon pääsevät prosessit odottavat, kunnes mikään prosessi ei ole varannut kriittistä osaa. Aina kun mikä tahansa prosessi odottaa, se tarkistaa jatkuvasti semaforin arvon (katso tätä riviä, kun (s==0); P-toiminnassa) ja hukkaa CPU-syklin.
On myös mahdollisuus spinlockiin, koska prosessit jatkavat pyörimistä odottaessaan lukitusta. Tämän välttämiseksi alla esitetään toinen toteutus.
kaksiulotteinen matriisiohjelma c
Toteutus: Semaforin laskenta
CPP struct Semaphore { int value; // q contains all Process Control Blocks(PCBs) // corresponding to processes got blocked // while performing down operation. Queueq; }; P(Semafori s) { s.arvo = s.arvo - 1; if (s.value< 0) { // add process to queue // here p is a process which is currently executing q.push(p); block(); } else return; } V(Semaphore s) { s.value = s.value + 1; if (s.value <= 0) { // remove process p from queue Process p = q.pop(); wakeup(p); } else return; }> Java import java.util.LinkedList; import java.util.Queue; // semaphore class class Semaphore { // our value int value; Queueq; public Semafori(int arvo) { this.value = arvo; q = uusi LinkedList(); } public void P(Prosessi p) { arvo--; jos (arvo< 0) { q.add(p); p.block(); } } public void V() { value++; if (value <= 0) { Process p = q.remove(); p.wakeup(); } } }> Python 3 import heapq # Global Variable to track the Processes going into Critical Section COUNTER=1 class Semaphore: def __init__(self,value): # Value of the Semaphore passed to the Constructor self.value=value # The Waiting queue which will be using the heapq module of Python self.q=list() def getSemaphore(self): ''' Function to print the Value of the Semaphore Variable ''' print(f'Semaphore Value: {self.value}') def block(process): print(f'Process {process} Blocked.') def wakeup(process): print(f'Process {process} Waked Up and Completed it's work.') def P(s): global COUNTER s.value=s.value-1 if(s.value<0): heapq.heappush(s.q,COUNTER) block(COUNTER) else: print(f'Process {COUNTER} gone inside the Critical Section.') COUNTER+=1 return def V(s): global COUNTER s.value=s.value+1 if(s.value<=0): p=heapq.heappop(s.q) wakeup(p) COUNTER-=1 else: print(f'Process {COUNTER} completed it's work.') COUNTER-=1 return # Can Pass the Value of the Counting Semaphore to the Class Constructor # Example for Counting Semaphore value as 2 s1=Semaphore(2) s1.getSemaphore() P(s1) s1.getSemaphore() P(s1) s1.getSemaphore() P(s1) s1.getSemaphore() V(s1) s1.getSemaphore() V(s1) s1.getSemaphore() V(s1) s1.getSemaphore() # This Code is Contributed by Himesh Singh Chauhan> C# using System.Collections.Generic; public class Semaphore { public int value; // q contains all Process Control Blocks(PCBs) // corresponding to processes got blocked // while performing down operation. Queueq = uusi jono(); public void P(Prosessi p) { arvo--; jos (arvo< 0) { // add process to queue q.Enqueue(p); p.block(); } } public void V() { value++; if (value <= 0) { // remove process p from queue Process p = q.Dequeue(); p.wakeup(); } } }> JavaScript // Define a Semaphore object function Semaphore() { this.value = 0; this.q = []; // Initialize an array to act as a queue } // Implement the P operation Semaphore.prototype.P = function(p) { this.value = this.value - 1; if (this.value < 0) { // Add process to queue this.q.push(p); // Assuming block() and wakeup() functions are defined elsewhere block(); } }; // Implement the V operation Semaphore.prototype.V = function() { this.value = this.value + 1; if (this.value <= 0) { // Remove process p from queue var p = this.q.shift(); // Assuming wakeup() function is defined elsewhere wakeup(p); } }; // This code is contributed by Susobhan Akhuli> Tässä toteutuksessa aina kun prosessi odottaa, se lisätään siihen semaforiin liittyvien prosessien odotusjonoon. Tämä tehdään prosessin järjestelmäkutsulohkon () kautta. Kun prosessi on valmis, se kutsuu signaalifunktiota ja yhtä prosessia jonossa jatketaan. Se käyttää wakeup()-järjestelmäkutsua.
Semaforien edut:
- Yksinkertainen ja tehokas prosessin synkronointimekanismi
- Tukee koordinaatiota useiden prosessien välillä
- Tarjoaa joustavan ja vankan tavan hallita jaettuja resursseja.
- Sitä voidaan käyttää kriittisten osien toteuttamiseen ohjelmassa.
- Sitä voidaan käyttää kilpailuolosuhteiden välttämiseen.
Semaforien haitat:
- Se voi johtaa suorituskyvyn heikkenemiseen odotus- ja signaalitoimintoihin liittyvien ylimääräisten kulujen vuoksi.
- Voi johtaa lukkiutumiseen, jos sitä käytetään väärin.
- Dijkstra ehdotti sitä vuonna 1965, mikä on erittäin merkittävä tekniikka samanaikaisten prosessien hallitsemiseksi käyttämällä yksinkertaista kokonaislukuarvoa, joka tunnetaan semaforina. Semafori on yksinkertaisesti kokonaislukumuuttuja, joka jaetaan säikeiden kesken. Tätä muuttujaa käytetään ratkaisemaan kriittisen osion ongelma ja saavuttamaan prosessin synkronointi moniprosessointiympäristössä.
- Se voi aiheuttaa ohjelman suorituskykyongelmia, jos sitä ei käytetä oikein.
- Viankorjaus ja ylläpito voi olla vaikeaa.
- Se voi olla altis kilpailuolosuhteille ja muille synkronointiongelmille, jos sitä ei käytetä oikein.
- Se voi olla alttiina tietyntyyppisille hyökkäyksille, kuten palvelunestohyökkäyksille.