Download presentation
Presentation is loading. Please wait.
1
Steve’s Concurrency Slides
2
What is Synchronization?
Ability of Two or More Serial Processes to Interact During Their Execution to Achieve Common Goal Recognition that “Today’s” Applications Require Multiple Interacting Processes Client/Server and Multi-Tiered Architectures Inter-Process Communication via TCP/IP Fundamental Concern: Address Concurrency Control Access to Shared Information Historically Supported in Database Systems Currently Available in Many Programming Languages
3
Thread Synchronization
Suppose X and Y are Concurrently Executing in Same Address Space What are Possibilities? What Does Behavior at Left Represent? Synchronous Execution! X Does First Part of Task Y Next Part Depends on X X Third Part Depends on Y Threads Must Coordinate Execution of Their Effort X Y 1 2 3
4
Thread Synchronization
Now, What Does Behavior at Left Represent? Asynchronous Execution! X Does First Part of Task Y Does Second Part Concurrent with … X Doing Third Part What are Issues? X Y 1 2 3 Will Second Part Still Finish After Third Part? Will Second Part Now Finish Before Third Part? What Happens if Variables are Shared?
5
What are Potential Problems without Synchronization?
Data Inconsistency Lost-Update Problem Impact on Correctness of Executing Software Deadlock Two Processes Each Hold Unique Resource and Want Resource of Other Process Processes Wait Forever Non-Determinacy of Computations Behavior of Computation Different for Different Executions Two Process Produce Different Results When Executed More than Once on Same Data
6
What are Classic Synchronization Techniques?
Goal: Shared Variables and Resources Two Approaches: Critical Sections Define a Segment of Code as Critical Section Once Execution Enters Code Segment it Cannot be Interrupted by Scheduler Release Point for Critical Section for Interrupts Semaphores Proposed in 1960s by E. Dijkstra Utilizes ADTs to Design and Implement Behavior that Guarantees Consistency and Non-Deadlock
7
Critical Sections Two Processes Share “balance” Data Item
Remember, Assignment is Not Atomic, but May Correspond to Multiple Assembly Instructions What is Potential Problem? shared float balance; Code for p Code for p2 balance = balance + amount; balance = balance - amount; p1 p2 balance
8
Critical Sections Recall the Code Below
What Happens if Time Slice Expires at Arrow and an Interrupt is Generated? shared double balance; Code for p Code for p2 balance = balance + amount; balance = balance - amount; Code for p Code for p2 load R1, balance load R1, balance load R2, amount load R2, amount add R1, R2 sub R1, R2 store R1, balance store R1, balance
9
Critical Sections (continued)
There is a Race to Execute Critical Sections Sections May Be Different Code in Different Processes: Cannot Detect With Static Analysis Results of Multiple Execution Are Not Determinate Need an OS Mechanism to Resolve Races If p1 Wins, R1 and R2 Added to Balance - Okay If p2 Wins, its Changed Balance Different from One Held by p1 which Adds/Writes Wrong Value Code for p Code for p2 load R1, balance load R1, balance load R2, amount load R2, amount add R1, R2 sub R1, R2 store R1, balance store R1, balance
10
One Solution: Disabling Interrupts
In Code Below, Disable Interrupts What are Potential Problems? Interrupts Could Be Disabled Arbitrarily Long Were Trusting Software Engineers Unintentional(Infinite Loop) or Malicious Code Concurrent PLs Enforce Primitives at Compile Really Only Want to Prevent P1 and P2 From Interfering With One Another Another Solution: Using Shared “Lock” Variable shared double balance; Code for p Code for p2 disableInterrupts(); disableInterrupts(); balance = balance + amount; balance = balance - amount; enableInterrupts(); enableInterrupts();
11
Using a Lock Variable Shared lock Flag Initialized to False
First Process to be Active Sets lock to TRUE Enter Critical Section Change balance Set lock to FALSE Leave Critical Section Where are Two Trouble Spots? shared boolean lock = FALSE; shared double balance; Code for p1 /* Acquire the lock */ while(lock) ; lock = TRUE; /* Execute critical sect */ balance = balance + amount; /* Release lock */ lock = FALSE; Code for p2 What if Interrupt Occurs Here? What if Interrupt Occurs Here?
12
Using a Lock Variable p2 p1
shared boolean lock = FALSE; shared double balance; Code for p1 /* Acquire the lock */ while(lock) ; lock = TRUE; /* Execute critical sect */ balance = balance + amount; /* Release lock */ lock = FALSE; Code for p2 /* Acquire the lock */ while(lock) ; lock = TRUE; /* Execute critical sect */ balance = balance + amount; /* Release lock */ lock = FALSE; Blocked at while p2 p1 lock = TRUE Interrupt Interrupt lock = FALSE Interrupt
13
Lock Manipulation Consider the Following enter/exit Primitives that Will be Utilized to Insure No Interrupts During How Does Code Below Insure that Interrupts are Disabled? enter(lock) { exit(lock) { disableInterrupts(); disableInterrupts(); /* Loop until lock is TRUE */ lock = FALSE; while(lock) { enableInterrupts(); /* Let interrupts occur */ } enableInterrupts(); disableInterrupts(); } lock = TRUE; What Occurs Here? Remember, Need Location for Interrupts to Occur During Attempt to Acquire Lock!
14
Utilizing Enter and Exit
Example: List Manipulator Add or Delete an Element From a List Adjust the List Descriptor, e.g., Length Modify List Content and Length A Transaction is a List of Operations The System Begins to Execute a Transaction Execution Must Occur on All Operations that Comprise Transaction Without Interruption Or, the Transaction Must Not Execute Any Operations at All Concept of Atomic Transaction
15
Processing Two Transactions
shared boolean lock2 = FALSE;lock1 = FALSE; shared list L; Code for p Code for p2 /* Enter CS to delete elt */ /* Enter CS to update len */ enter(lock1); enter(lock2); <delete element>; <update length>; /* Exit CS */ /* Exit CS */ exit(lock1); exit(lock2); <intermediate computation>; <intermediate computation> /* Enter CS to update len */ /* Enter CS to add elt */ enter(lock2); enter(lock1); <update length>; <add element>; exit(lock2); exit(lock1); Notice Any Problems with Code for Processes? Interrupt of p1 After Delete But Before Update If p2 Adds Element and Updates Length, Inconsistency Occurs
16
Deadlock Why and How Does Deadlock Occur? Code for p1 Code for p2
shared boolean lock1 = FALSE; lock2 = FALSE;shared list L; Code for p Code for p2 /* Enter CS to delete elt */ /* Enter CS to upd len */ enter(lock1); enter(lock2); <delete element>; <update length>; <intermediate computation>; <intermediate comp> /* Enter CS to update len */ /* Enter CS to add elt */ enter(lock2); enter(lock1); <update length>; <add element>; /* Exit both CS */ /* Exit both CS */ exit(lock1); exit(lock2); exit(lock2); exit(lock1); Why and How Does Deadlock Occur?
17
Coordinating Processes
Can Synchronize With FORK, JOIN & QUIT Terminate Processes With QUIT to Synchronize Create Processes Whenever Critical Section is Complete See Figure 8.7 Problems with All Approaches so Far Reliance on Software Engineers Error Prone and Difficult to Enforce Alternative is to Create OS Primitives Similar to the enter/exit Primitives
18
Some Constraints for “Ideal” Synchronization Mechanism
Processes will Enter Critical Sections Mutual Exclusion: Only One Process at any One Time in Allowed in the CS Only Processes Competing for a CS are Involved in Resolving Who Enters the CS Once a Process Attempts to Enter its CS, it Cannot be Postponed Indefinitely After Requesting Entry, Only a Bounded Number of Other Processes May Enter Before the Requesting Process Latter Two Points Prevent Starvation!
19
Assumptions About Solutions
Memory Read/Writes Are Indivisible Process A Reads X; Process B Writes X Either A Reads X; B Writes X B Writes X; A Reads X Simultaneous Attempts Result in Some Arbitrary Order of Access There is No Priority Among the Processes Relative Speeds of the Processes/Processors is Unknown Processes Are Cyclic and Sequential
20
Dijkstra Semaphore Classic Paper Describes Several Software Attempts to Solve the Problem (See Exercise 4, Section 8.6) Dijkstra First Found a Software Solution Then Proposed Simpler Hardware-Based Solution What is a Semaphore S? A Nonnegative Integer Variable Can Only Be Changed or Tested by Two Indivisible Functions: For V(s), No Interrupt is Possible For P(s), Interrupt During {wait}; Only V(s): [s = s + 1] P(s): [while(s == 0){wait}; s = s - 1]
21
How Do P & V Work? What is the Initial Value of Binary Semaphore?
Initial Value Set as Part of Shared Variable semaphore mutex = 1; Followed by Spawning of Two or More Processes What Does it Mean When mutex = 0? Process X Executed P(mutex) with mutex = 1 What About Other Processes Trying P(mutex)? Others Wait Until Process X Does V(mutex) If X is Interrupt Before V, Others Still Wait V(mutex): [mutex = mutex + 1] P(mutex): [while(mutex == 0){wait}; mutex = mutex - 1]
22
Using Semaphores to Solve the Canonical Problem
proc_0() { proc_1() { while(TRUE) { while(TRUE { <compute section>; <compute section>; P(mutex); P(mutex); <critical section>; <critical section>; V(mutex); V(mutex); } } } } semaphore mutex = 1; // Shared variable fork(proc_0, 0); fork(proc_1, 0); What if First P(mutex); Called by proc_0? s = 1 while false so s = 0 What if Interrupt Occurs in CS of proc_0? proc_1() Waits Until proc_0 Resumes When CS Finishes V is Fired to Set s = 1 V(s):[s = s + 1] P(s):[while(s==0) {wait}; s = s - 1]
23
Shared Account Problem
proc_0() { proc_1() { /* Enter the CS */ /* Enter the CS */ P(mutex); P(mutex); balance += amount; balance -= amount; V(mutex); V(mutex); } } semaphore mutex = 1; // Shared variable fork(proc_0, 0); fork(proc_1, 0); Assume Following Values: balance = 200 amount = 50 amount = 75 What are Possible Results? Is there a Lost Update? V(s):[s = s + 1] P(s):[while(s==0) {wait}; s = s - 1]
24
If proc_0 Interrupted Waits proc_1
balance = 200 amount = 50 amount = 75 V(s):[s = s + 1] P(s):[while(s==0) {wait};s=s-1] proc_0() { proc_1() { /* Enter the CS */ /* Enter the CS */ P(mutex); P(mutex); balance += amount; balance -= amount; V(mutex); V(mutex); } } proc_0 Executes P First If proc_0 Interrupted Waits proc_1 Eventually proc_0 Resumes balance = 250 proc_0 Executes V proc_1 Executes P Sets balance = 175 proc_1 Executes V proc_1 Executes P First If proc_1 Interrupted proc_0 Waits Eventually proc_1 Resumes balance = 125 proc_1 Executes V proc_0 Executes P Sets balance = 175 proc_0 Executes V
25
Two Shared Variables What is Execution Process That Guarantees
proc_A() { while(TRUE) { <compute section A1>; update(x); /* Signal proc_B */ V(s1); <compute section A2>; /* Wait for proc_B */ P(s2); retrieve(y); } semaphore s1 = 0; semaphore s2 = 0; fork(proc_A, 0); fork(proc_B, 0); proc_B() { while(TRUE) { /* Wait for proc_A */ P(s1); retrieve(x); <compute section B1>; update(y); /* Signal proc_A */ V(s2); <compute section B2>; } What is Execution Process That Guarantees x and y are Read After They’re Written?
26
Execution Process Two Shared Variables
integer x,y; semaphore s1=0; semaphore s2=0; proc_A() { while(TRUE) { <compute section A1>; update(x); /* Signal proc_B */ V(s1); <compute section A2>; /* Wait for proc_B */ P(s2); retrieve(y); } P(s1) will not Execute Until V(s1) sets s1 to 1 x Written Before Read proc_B() { while(TRUE) { /* Wait for proc_A */ P(s1); retrieve(x); <compute section B1>; update(y); /* Signal proc_A */ V(s2); <compute section B2>; } P(s2) will not Execute Until V(s2) sets s2 to 1 y Written Before Read Doesn’t Matter if Interrupt Occurs Anywhere Read of Written Data Only After Semaphore Secured
27
Bounded Buffer Producer/Consumer Model Processes Communicate by
Producer Obtains Empty Buffer fr. Pool Producer Fills Buffer & Places in Full Pool Consumer Obtains Info. By Picking Buffer fr. Full Pool Consumer Copies Info Out of Buffer Consumer Places Buffer in Empty Pool N Fixed Number of Buffers Utilize Counting/Binary Semaphores Producer Consumer Empty Pool Full Pool
28
Bounded Buffer consumer() { producer() { buf_type *next, *here;
while(TRUE) { /* Claim full buffer */ P(full); P(mutex); here = obtain(full); V(mutex); copy_buffer(here, next); release(here, emptyPool); /* Signal an empty buffer */ V(empty); consume_item(next); } producer() { buf_type *next, *here; while(TRUE) { produce_item(next); /* Claim an empty */ P(empty); P(mutex); here = obtain(empty); V(mutex); copy_buffer(next, here); release(here, fullPool); /* Signal a full buffer */ V(full); } semaphore mutex = 1; /* A binary semaphore */ semaphore full = 0; /* A general (counting) semaphore */ semaphore empty = N; /* A general (counting) semaphore */ buf_type buffer[N]; fork(producer, 0); fork(consumer, 0);
29
Execution Process Bounded Buffer
semaphore mutex = 1; semaphore full = 0; semaphore empty = N; buf_type buffer[N]; producer() { buf_type *next, *here; while(TRUE) { produce_item(next); /* Claim an empty */ P(empty); P(mutex); here = obtain(empty); V(mutex); copy_buffer(next, here); release(here, fullPool); /* Signal a full buffer */ V(full); } Producers Want Empty Buffers Consumers Want Full Buffers Distinct Empty Buffer Goes to Only 1 Producer consumer() { buf_type *next, *here; while(TRUE) { /* Claim full buffer */ P(full); P(mutex); here = obtain(full); V(mutex); copy_buffer(here, next); release(here, emptyPool); /* Signal an empty buffer */ V(empty); consume_item(next); } Protect Changes to Full Pool Only One Process Accesses Full Pool Full Buffer Now Available Empty Buffer Now Available Protect Changes to Empty Pool
30
The Readers-Writers Problem
Establish Protocol Regarding R/W Access to Shared Resource Writer Excludes Readers (1 W, No R or n R) Write Allows Readers (1W and n R) What is Difference re. Consistency? What is Readers-Writers Problem? Shared Resource (e.g., a File) Readers Share with Other Readers Writer has Exclusive Access What are Potential Problems? When does Write Occur? Can Readers Starve out Writer?
31
Readers-Writers Problem
Shared Resource
32
Readers-Writers Problem
Shared Resource
33
Readers-Writers Problem
Shared Resource
34
A First Solution First Reader Competes With Writers
while(TRUE) { <other computing>; P(mutex); readCount++; if(readCount == 1) P(writeBlock); V(mutex); /* Critical section */ access(resource); readCount--; if(readCount == 0) V(writeBlock); } resourceType *resource; int readCount = 0; semaphore mutex = 1; semaphore writeBlock = 1; fork(reader, 0); fork(writer, 0); writer() { while(TRUE) { <other computing>; P(writeBlock); /* Critical section */ access(resource); V(writeBlock); } First Reader Competes With Writers Last Reader Signals Writers Any Writer Must Wait for All Readers Readers Can Starve Writers “Updates” Can Be Delayed Forever May Not Be What We Want
35
Writer Takes Precedence
reader() { while(TRUE) { <other computing>; P(writePending); P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); V(writePending); access(resource); readCount--; if(readCount == 0) V(writeBlock); } int readCount=0, writeCount=0; semaphore mutex1= 1, mutex2= 1; semaphore readBlock = 1, writeBlock = 1, writePending = 1; fork(reader, 0); fork(writer, 0); writer() { while(TRUE) { <other computing>; P(mutex2); writeCount++; if(writeCount ==1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); }
36
Only Held by One Reader at Time Mutex1 Protects readCount from
How Do Different Semaphores Work? semaphore mutex1= 1, mutex2= 1; semaphore readBlock = 1; semaphore writeBlock = 1; semaphore writePending = 1; Only Held by One Reader at Time reader() { while(TRUE) { <other computing>; P(writePending); P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); V(writePending); access(resource); readCount--; if(readCount == 0) V(writeBlock); } Allow Only One Reader If Writer Waiting Only Reader? Prevent Writer Mutex1 Protects readCount from Multiple Readers Write can Now Proceed Only Reader? Allow Writer
37
How Do Different Semaphores Work?
semaphore mutex1= 1, mutex2= 1; semaphore readBlock = 1; semaphore writeBlock = 1; semaphore writePending = 1; writer() { while(TRUE) { <other computing>; P(mutex2); writeCount++; if(writeCount ==1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); } Only Writer? Mutex2 Protects writeCount from Multiple Writers Prevent Reader Only Held by One Writer at Time Other Writers and Readers Can Proceed Only Writer? Allow Reader
38
How Do Different Semaphores Work?
semaphore mutex1= 1, mutex2= 1; semaphore readBlock = 1; semaphore writeBlock = 1; semaphore writePending = 1; reader() { while(TRUE) { <other computing>; P(writePending); P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); V(writePending); access(resource); readCount--; if(readCount == 0) V(writeBlock); } writer() { while(TRUE) { <other computing>; P(mutex2); writeCount++; if(writeCount ==1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); }
39
Monitors Specialized Form of ADT Encapsulates Implementation
Public Interface (Types & Functions) Only One Process Can Be Executing (Invoking a Method) in the ADT at a Time One Shared Instance of ADT! monitor anADT { semaphore mutex = 1; // Implicit . . . public: proc_i(…) { P(mutex); // Implicit <processing for proc_i>; V(mutex); // Implicit };
40
Example: Shared Balance
Consider the Shared Balance Monitor Below. Each Method (credit/debit) Define Critical Section Hence, by its Definition … Methods Disable Interrupts at Start of Call and Re-enable Interrupts at End of Call monitor sharedBalance { double balance; public: credit(double amount) {balance += amount;}; debit(double amount) {balance -= amount;}; . . . };
41
Example: Readers & Writers
monitor readerWriter_1 { int numberOfReaders = 0; int numberOfWriters = 0; boolean busy = FALSE; public: startRead() { }; finishRead() { startWrite() { finishWrite() { reader(){ while(TRUE) { . . . startRead(); finishRead(); } fork(reader, 0); fork(reader, 0): fork(writer, 0); writer(){ while(TRUE) { . . . startWrite(); finishWrite(); }
42
Example: Readers & Writers
monitor readerWriter_1 { int numberOfReaders = 0; int numberOfWriters = 0; boolean busy = FALSE; public: startRead() { while(numberOfWriters != 0) ; numberOfReaders++; }; finishRead() { numberOfReaders-; startWrite() { numberOfWriters++; while( busy || (numberOfReaders > 0) ) ; busy = TRUE; }; finishWrite() { numberOfWriters--; busy = FALSE;
43
Example: Readers & Writers
monitor readerWriter_1 { int numberOfReaders = 0; int numberOfWriters = 0; boolean busy = FALSE; public: startRead() { while(numberOfWriters != 0); numberOfReaders++; }; finishRead() { numberOfReaders--; Deadlock can Occur! startWrite() { numberOfWriters++; while( busy || (numberOfReaders > 0) ) ; busy = TRUE; }; finishWrite() { numberOfWriters--; busy = FALSE;
44
Condition Variables Essentially an Event (As Defined Previously)
Global Condition Visible to All Methods Defined in Monitor -- Occurs Only Inside a Monitor Operations to Manipulate Condition Variable Wait: Suspend Invoking Process Until Another Executes a Signal Signal: Resume One Process If Any Are Suspended, Otherwise Do Nothing Queue: Return TRUE If There is at Least One Process Suspended on the Condition Variable Conditions Increase Complexity of Monitor Transcends Traditional Semaphore Capabilities
45
Second Try at Readers & Writers
monitor readerWriter_2 { int numberOfReaders = 0; boolean busy = FALSE; condition okToRead, okToWrite; public: // startRead and finishRead used by Readers startRead() { if(busy || // busy = TRUE implies writer (okToWrite.queue()) okToRead.wait(); numberOfReaders++; okToRead.signal(); }; finishRead() { numberOfReaders--; if(numberOfReaders == 0) okToWrite.signal();
46
Second Try at Readers & Writers
// startWrite and finishWrite Used by Writers startWrite() { if((numberOfReaders != 0) || busy) okToWrite.wait(); busy = TRUE; }; finishWrite() { busy = FALSE; if(okToRead.queue()) okToRead.signal() else okToWrite.signal() Each Method is Atomic! Cannot be Interrupted!
47
Example: Synchronizing Traffic
One-Way Tunnel Can Only Use Tunnel If No Oncoming Traffic OK to Use Tunnel If Traffic is Already Flowing the Right Way Differentiate Between Northbound and Southbound Traffic Reset Light from Red to Green (and Green to Red) to Control Flow
48
Example: Synchronizing Traffic
monitor tunnel { int northbound = 0, southbound = 0; trafficSignal nbSignal = RED, sbSignal = GREEN; condition busy; public: nbArrival() { if(southbound > 0) busy.wait(); northbound++; nbSignal = GREEN; sbSignal = RED; }; sbArrival() { if(northbound > 0) busy.wait(); southbound++; nbSignal = RED; sbSignal = GREEN;
49
Ex: Synchronizing Traffic (Continued)
depart(Direction exit) ( if(exit = NORTH { northbound--; if (northbound == 0) while(busy.queue()) busy.signal(); else if (exit == SOUTH) { southbound--; if(southbound == 0) } // SOUTH if } // NORTH if }; // depart method }; tunnel monitor
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.