logo

Semaforer i prosesssynkronisering

Semaforer er bare normale variabler som brukes til å koordinere aktivitetene til flere prosesser i et datasystem. De brukes til å håndheve gjensidig ekskludering, unngå raseforhold og implementere synkronisering mellom prosesser.

Prosessen med å bruke semaforer gir to operasjoner: vent (P) og signal (V). Venteoperasjonen reduserer verdien av semaforen, og signaloperasjonen øker verdien til semaforen. Når verdien av semaforen er null, vil enhver prosess som utfører en venteoperasjon bli blokkert inntil en annen prosess utfører en signaloperasjon.



Semaforer brukes til å implementere kritiske seksjoner, som er områder med kode som bare må utføres av én prosess om gangen. Ved å bruke semaforer kan prosesser koordinere tilgang til delte ressurser, for eksempel delt minne eller I/O-enheter.

En semafor er en spesiell type synkroniseringsdata som bare kan brukes gjennom spesifikke synkroniseringsprimitiver. Når en prosess utfører en venteoperasjon på en semafor, kontrollerer operasjonen om verdien av semaforen er>0. I så fall reduserer den verdien av semaforen og lar prosessen fortsette utførelsen; ellers blokkerer det prosessen på semaforen. En signaloperasjon på en semafor aktiverer en prosess blokkert på semaforen hvis noen, eller øker verdien på semaforen med 1. På grunn av denne semantikken kalles semaforer også tellesemaforer. Startverdien til en semafor bestemmer hvor mange prosesser som kan komme forbi venteoperasjonen.

annet hvis bash

Semaforer er av to typer:



  1. Binær semafor –
    Dette er også kjent som en mutex-lås. Den kan bare ha to verdier – 0 og 1. Verdien er initialisert til 1. Den brukes til å implementere løsningen av kritiske seksjonsproblemer med flere prosesser.
  2. Å telle semafor –
    Verdien kan variere over et ubegrenset domene. Den brukes til å kontrollere tilgang til en ressurs som har flere forekomster.

La oss nå se hvordan det gjør det.

Se først på to operasjoner som kan brukes til å få tilgang til og endre verdien av semaforvariabelen.

P-og-V-drift-i-OS



Noen punkter angående P- og V-drift:

java inneholder delstreng
  1. P-drift kalles også vente-, dvale- eller neddrift, og V-drift kalles også signal-, vekke- eller oppdrift.
  2. Begge operasjonene er atomære og semafor(er) initialiseres alltid til én. Her betyr atom den variabelen som lesing, modifisering og oppdatering skjer på samme tid/øyeblikk uten forkjøpsrett, dvs. mellom lesing, modifisering og oppdatering utføres ingen annen operasjon som kan endre variabelen.
  3. En kritisk del er omgitt av begge operasjonene for å implementere prosesssynkronisering. Se bildet nedenfor. Den kritiske delen av prosess P er mellom P- og V-drift.

La oss nå se hvordan den implementerer gjensidig ekskludering. La det være to prosesser P1 og P2 og en semafor s initialiseres som 1. Hvis anta at P1 går inn i sin kritiske seksjon, blir verdien av semafor s 0. Hvis P2 nå vil gå inn i sin kritiske seksjon, vil den vente til s> 0, dette kan bare skje når P1 fullfører sin kritiske seksjon og kaller V-operasjon på semafor s.

primitive datatyper i java

På denne måten oppnås gjensidig eksklusjon. Se på bildet nedenfor for detaljer som er en binær semafor.


Gjennomføring: Binære semaforer

C++
struct semaphore {    enum value(0, 1);  // q contains all Process Control Blocks (PCBs)  // corresponding to processes got blocked  // while performing down operation.  Queueq; }; P(semafor s) { if (s.verdi == 1) { s.verdi = 0;  } else { // legg prosessen til ventekøen q.push(P) sleep();  } } V(semafor s) { if (s.q er tom) { s.value = 1;  } else { // velg en prosess fra ventekøen. Prosess p = q.front();  // fjern prosessen fra å vente som den har blitt // sendt for CS q.pop();  vekke(p);  } } // Denne koden er modifisert av Susobhan Akhuli>
C
#include  #include #include struct semaphore{  Queueq;  int verdi; }; void P(struktur semafor s) { if (s.value == 1) { s.value = 0;  } annet { s.q.push(P);   sove();  } } void V(semafor s) { if (s.q er tom) { s.value = 1;  } else { // Få en prosess fra Waiting Queue Process p = q.front();  // Fjern prosessen fra å vente q.pop();  vekke(p);  } } int main() { printf('Dette er Hemish!!');    // Denne koden er bidratt av Himesh Singh Chauhan retur 0; } // Denne koden er modifisert av Susobhan Akhuli>
Java
import java.util.*; class Semaphore {  public enum Value { Zero, One }  public Queueq = ny LinkedList();  offentlig verdi verdi = Verdi.En;  public void P(Semaphore s, Process p) { if (s.value == Value.One) { s.value = Value.Zero;  } else { // legg prosessen til ventekøen q.add(p);  p.Søvn();  } } public void V(Semaphore s) { if (s.q.size() == 0) { s.value = Value.One;  } else { // velg en prosess fra ventekøen. Prosess p = q.peek();  // fjern prosessen fra å vente siden den har // blitt sendt for CS q.remove();  p.Wakeup();  } } }>
Python3
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 = ny kø();  public void P(Semaphore s, Process p) { if (s.value == value.One) { s.value = value.Zero;  } else { // legg prosessen til ventekøen q.Enqueue(p);  p.Søvn();  } } public void V(Semaphore s) { if (s.q.Count == 0) { s.value = value.One;  } else { // velg en prosess fra ventekøen. Prosess p = q.Peek();  // fjern prosessen fra å vente som den har blitt // sendt for CS q.Dequeue();  p.Wakeup();  } } }>
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);  }  } }>

Beskrivelsen ovenfor er for binær semafor som bare kan ta to verdier 0 og 1 og sikre gjensidig ekskludering. Det er en annen type semafor kalt tellesemafor som kan ta verdier større enn én.

Anta nå at det er en ressurs hvis antall forekomster er 4. Nå initialiserer vi S = 4 og resten er den samme som for binær semafor. Når prosessen vil ha den ressursen kaller den P eller venter på funksjon og når den er ferdig kaller den V eller signalfunksjon. Hvis verdien av S blir null, må en prosess vente til S blir positiv. Anta for eksempel at det er 4 prosesser P1, P2, P3, P4, og de kaller alle venteoperasjoner på S (initialisert med 4). Hvis en annen prosess P5 vil ha ressursen, bør den vente til en av de fire prosessene kaller signalfunksjonen og verdien til semaforen blir positiv.

Begrensninger:

  1. En av de største begrensningene til semafor er prioritert inversjon.
  2. Deadlock, anta at en prosess prøver å vekke en annen prosess som ikke er i dvaletilstand. Derfor kan en dødlås blokkere på ubestemt tid.
  3. Operativsystemet må holde styr på alle anrop for å vente og signalisere semaforen.

Problem i denne implementeringen av en semafor:

Hovedproblemet med semaforer er at de krever opptatt venting. Hvis en prosess er i den kritiske delen, vil andre prosesser som prøver å gå inn i den kritiske delen vente til den kritiske delen ikke er opptatt av noen prosess. Når en prosess venter, sjekker den kontinuerlig for semaforverdi (se på denne linjen mens (s==0); i P-drift) og sløsing med CPU-syklus.

Det er også en sjanse for spinlock ettersom prosessene fortsetter å snurre mens de venter på låsen. For å unngå dette er en annen implementering gitt nedenfor.

java if-setning

Gjennomføring: Telle semafor

CPP
struct Semaphore {  int value;  // q contains all Process Control Blocks(PCBs)  // corresponding to processes got blocked  // while performing down operation.  Queueq; }; P(Semaphore s) { s.value = s.value - 1;  if (s.verdi< 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;  offentlig semafor(int verdi) { this.value = verdi;  q = new LinkedList();  } offentlig void P(Prosess p) { verdi--;  hvis (verdi< 0) {  q.add(p);  p.block();  }  }  public void V()  {  value++;  if (value <= 0) {  Process p = q.remove();  p.wakeup();  }  } }>
Python3
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 = ny kø();  public void P(Prosess p) { verdi--;  hvis (verdi< 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>

I denne implementeringen, når prosessen venter, blir den lagt til en ventekø av prosesser knyttet til den semaforen. Dette gjøres gjennom systemanropsblokken() på den prosessen. Når en prosess er fullført kaller den signalfunksjonen og en prosess i køen gjenopptas. Den bruker wakeup() systemkallet.

Fordeler med semaforer:

  • En enkel og effektiv mekanisme for prosesssynkronisering
  • Støtter koordinering mellom flere prosesser
  • Gir en fleksibel og robust måte å administrere delte ressurser på.
  • Den kan brukes til å implementere kritiske seksjoner i et program.
  • Den kan brukes til å unngå løpsforhold.

Ulemper med semaforer:

  • Det kan føre til ytelsesforringelse på grunn av overhead forbundet med vente- og signaloperasjoner.
  • Kan føre til vranglås hvis den brukes feil.
  • Det ble foreslått av Dijkstra i 1965, som er en veldig viktig teknikk for å administrere samtidige prosesser ved å bruke en enkel heltallsverdi, som er kjent som en semafor. En semafor er ganske enkelt en heltallsvariabel som deles mellom tråder. Denne variabelen brukes til å løse det kritiske seksjonsproblemet og for å oppnå prosesssynkronisering i multiprosesseringsmiljøet.
  • Det kan forårsake ytelsesproblemer i et program hvis det ikke brukes riktig.
  • Det kan være vanskelig å feilsøke og vedlikeholde.
  • Den kan være utsatt for løpsforhold og andre synkroniseringsproblemer hvis den ikke brukes riktig.
  • Det kan være sårbart for visse typer angrep, for eksempel tjenestenektangrep.