logo

Semafori procesu sinhronizācijā

Semafori ir tikai normāli mainīgie, ko izmanto, lai koordinētu vairāku procesu darbības datorsistēmā. Tos izmanto, lai īstenotu savstarpēju izslēgšanu, izvairītos no sacīkšu apstākļiem un īstenotu sinhronizāciju starp procesiem.

Semaforu izmantošanas process nodrošina divas darbības: gaidīšana (P) un signāls (V). Gaidīšanas darbība samazina semafora vērtību, bet signāla darbība palielina semafora vērtību. Ja semafora vērtība ir nulle, jebkurš process, kas veic gaidīšanas darbību, tiks bloķēts, līdz cits process veiks signāla darbību.



Semafori tiek izmantoti, lai ieviestu kritiskās sadaļas, kas ir koda reģioni, kas vienlaikus jāizpilda tikai vienam procesam. Izmantojot semaforus, procesi var koordinēt piekļuvi koplietotajiem resursiem, piemēram, koplietotajai atmiņai vai I/O ierīcēm.

Semafors ir īpašs sinhronizācijas datu veids, ko var izmantot tikai, izmantojot īpašus sinhronizācijas primitīvus. Kad process semaforam veic gaidīšanas darbību, darbība pārbauda, ​​vai semafora vērtība ir>0. Ja tā, tas samazina semafora vērtību un ļauj procesam turpināt tā izpildi; pretējā gadījumā tas bloķē procesu semaforā. Signāla darbība semaforā aktivizē procesu, kas bloķēts semaforā, ja tāds ir, vai palielina semafora vērtību par 1. Šīs semantikas dēļ semaforus sauc arī par skaitīšanas semaforiem. Sākotnējā semafora vērtība nosaka, cik daudz procesu var pāriet no gaidīšanas darbības.

Semafori ir divu veidu:



  1. Binārais semafors -
    To sauc arī par mutex slēdzeni. Tam var būt tikai divas vērtības – 0 un 1. Tā vērtība tiek inicializēta uz 1. To izmanto, lai īstenotu kritisko sekcijas problēmu risinājumu ar vairākiem procesiem.
  2. Semafora skaitīšana -
    Tās vērtība var svārstīties neierobežotā domēnā. To izmanto, lai kontrolētu piekļuvi resursam, kuram ir vairāki gadījumi.

Tagad redzēsim, kā tas to dara.

Vispirms apskatiet divas darbības, kuras var izmantot, lai piekļūtu semafora mainīgā vērtībai un mainītu to.

P-un-V-operation-in-OS



Daži punkti par P un V darbību:

  1. P darbību sauc arī par gaidīšanas, miega vai lejupslīdes darbību, un V darbību sauc arī par signāla, pamošanās vai augšupdarbības darbību.
  2. Abas darbības ir atomāras, un semafors(-i) vienmēr tiek inicializēts uz vienu. Šeit atoms nozīmē mainīgo, kura lasīšana, modificēšana un atjaunināšana notiek vienlaikus/mirklī bez priekšrocībām, t.i., starp lasīšanu, modificēšanu un atjaunināšanu netiek veikta neviena cita darbība, kas varētu mainīt mainīgo.
  3. Kritisku sadaļu ieskauj abas darbības, lai īstenotu procesa sinhronizāciju. Skatiet zemāk redzamo attēlu. Procesa P kritiskā sadaļa atrodas starp P un V darbību.

kā atvērt json failu

Tagad redzēsim, kā tā īsteno savstarpēju izslēgšanu. Lai ir divi procesi P1 un P2 un semafors s tiek inicializēts kā 1. Ja pieņemsim, ka P1 ieiet savā kritiskajā sadaļā, tad semafora s vērtība kļūst 0. Ja P2 vēlas iekļūt savā kritiskajā sadaļā, tad tas gaidīs līdz s.> 0, tas var notikt tikai tad, kad P1 pabeidz savu kritisko posmu un izsauc V operāciju semaforā s.

Tādā veidā tiek panākta savstarpēja izslēgšana. Sīkāku informāciju skatiet zemāk esošajā attēlā, kas ir binārais semafors.


Īstenošana: Binārie semafori

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(semafors s) { if (s.value == 1) { s.value = 0;  } else { // pievienot procesu gaidīšanas rindai q.push(P) sleep();  } } V(semafors s) { if (s.q ir tukšs) { s.vērtība = 1;  } else { // atlasīt procesu no gaidīšanas rindas Process p = q.front();  // noņemt procesu no gaidīšanas, jo tas ir nosūtīts // CS q.pop();  pamošanās(p);  } } // Šo kodu ir modificējis Susobhan Akhuli>
C
#include  #include #include struct semaphore{  Queueq;  int vērtība; }; void P(strukturēt semaforu s) { if (s.value == 1) { s.value = 0;  } else { s.q.push(P);   Gulēt();  } } void V(semafors s) { if (s.q ir tukšs) { s.value = 1;  } else { // Iegūt procesu no gaidīšanas rindas Process p = q.front();  // Noņemt procesu no gaidīšanas q.pop();  pamošanās(p);  } } int main() { printf('Tas ir hemish!!');    // Šī koda autors ir Himesh Singh Chauhan return 0; } // Šo kodu ir modificējis Susobhan Akhuli>
Java
import java.util.*; class Semaphore {  public enum Value { Zero, One }  public Queueq = jauns LinkedList();  public Value value = Value.One;  public void P(semafors s, process p) { if (s.value == Value.One) { s.value = Value.Zero;  } else { // pievienot procesu gaidīšanas rindai q.add(p);  p.Miegs();  } } public void V(Semafors s) { if (s.q.size() == 0) { s.value = Value.One;  } else { // atlasīt procesu no gaidīšanas rindas Process p = q.peek();  // noņemt procesu no gaidīšanas, jo // tas ir nosūtīts 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 = jauna rinda();  public void P(Semafors s, Process p) { if (s.value == value.One) { s.value = value.Zero;  } else { // pievienot procesu gaidīšanas rindai q.Enqueue(p);  p.Miegs();  } } public void V(Semafors s) { if (s.q.Count == 0) { s.value = value.One;  } else { // atlasīt procesu no gaidīšanas rindas Process p = q.Peek();  // noņemt procesu no gaidīšanas, jo tas ir nosūtīts // 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);  }  } }>

Iepriekš sniegtais apraksts attiecas uz bināro semaforu, kas var iegūt tikai divas vērtības 0 un 1 un nodrošināt savstarpēju izslēgšanu. Ir vēl viens semafora veids, ko sauc par skaitīšanas semaforu, kas var iegūt vērtības, kas ir lielākas par vienu.

iemet metienus java

Tagad pieņemsim, ka ir resurss, kura gadījumu skaits ir 4. Tagad mēs inicializējam S = 4 un pārējais ir tāds pats kā binārajam semaforam. Ikreiz, kad process vēlas šo resursu, tas izsauc P vai gaida funkciju un, kad tas ir paveikts, izsauc V vai signāla funkciju. Ja S vērtība kļūst par nulli, procesam ir jāgaida, līdz S kļūst pozitīvs. Piemēram, pieņemsim, ka ir 4 procesi P1, P2, P3, P4, un tie visi izsauc gaidīšanas operāciju S (inicializēts ar 4). Ja cits process P5 vēlas resursu, tam vajadzētu gaidīt, līdz viens no četriem procesiem izsauc signāla funkciju un semafora vērtība kļūst pozitīva.

Ierobežojumi:

  1. Viens no lielākajiem semafora ierobežojumiem ir prioritātes inversija.
  2. Strupceļš, pieņemsim, ka process mēģina pamodināt citu procesu, kas nav miega stāvoklī. Tāpēc strupceļš var bloķēties uz nenoteiktu laiku.
  3. Operētājsistēmai ir jāseko līdzi visiem zvaniem, lai gaidītu un signalizētu uz semaforu.

Problēma šajā semafora īstenošanā:

Galvenā problēma ar semaforiem ir tāda, ka tiem ir nepieciešama aizņemta gaidīšana. Ja process atrodas kritiskajā sadaļā, citi procesi, kas mēģina iekļūt kritiskajā sadaļā, gaidīs, līdz kritisko sadaļu neaizņem neviens process. Ikreiz, kad kāds process gaida, tas nepārtraukti pārbauda semafora vērtību (skatiet šo rindiņu, kamēr (s==0); P darbībā) un izšķērdē CPU ciklu.

Pastāv arī bloķēšanas iespēja, jo procesi turpina griezties, gaidot bloķēšanu. Lai no tā izvairītos, tālāk ir sniegta cita ieviešana.

Īstenošana: Skaitīšanas semafors

CPP
struct Semaphore {  int value;  // q contains all Process Control Blocks(PCBs)  // corresponding to processes got blocked  // while performing down operation.  Queueq; }; P(semafora s) { s.vērtība = s.vērtība — 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 Semafors(int vērtība) { this.value = vērtība;  q = jauns LinkedList();  } public void P(Process p) { value--;  ja (vērtība< 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 = jauna rinda();  public void P(Process p) { vērtība--;  ja (vērtība< 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>

Šajā implementācijā ikreiz, kad process gaida, tas tiek pievienots gaidīšanas rindai ar procesiem, kas saistīti ar šo semaforu. Tas tiek darīts, izmantojot sistēmas izsaukuma bloku () šajā procesā. Kad process ir pabeigts, tas izsauc signāla funkciju un tiek atsākts viens process rindā. Tas izmanto sistēmas izsaukumu wakeup ().

Semaforu priekšrocības:

  • Vienkāršs un efektīvs procesu sinhronizācijas mehānisms
  • Atbalsta koordināciju starp vairākiem procesiem
  • Nodrošina elastīgu un stabilu veidu, kā pārvaldīt koplietotos resursus.
  • To var izmantot, lai ieviestu programmas kritiskās sadaļas.
  • To var izmantot, lai izvairītos no sacensību apstākļiem.

Semaforu trūkumi:

  • Tas var izraisīt veiktspējas pasliktināšanos ar gaidīšanas un signāla darbībām saistītās pieskaitāmās izmaksas.
  • Var izraisīt strupceļu, ja to lieto nepareizi.
  • To ierosināja Dijkstra 1965. gadā, kas ir ļoti nozīmīgs paņēmiens vienlaicīgu procesu pārvaldībai, izmantojot vienkāršu vesela skaitļa vērtību, kas ir pazīstama kā semafors. Semafors ir vienkārši vesels mainīgais, kas tiek koplietots starp pavedieniem. Šis mainīgais tiek izmantots, lai atrisinātu kritiskās sadaļas problēmu un panāktu procesa sinhronizāciju daudzapstrādes vidē.
  • Tas var izraisīt programmas veiktspējas problēmas, ja to neizmanto pareizi.
  • Var būt grūti atkļūdot un uzturēt.
  • Ja to neizmanto pareizi, tas var būt pakļauts sacensību apstākļiem un citām sinhronizācijas problēmām.
  • Tas var būt neaizsargāts pret noteikta veida uzbrukumiem, piemēram, pakalpojumu liegšanas uzbrukumiem.