0% found this document useful (0 votes)
10 views

6 1 Process Synchronization

Uploaded by

csreesowmya22
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

6 1 Process Synchronization

Uploaded by

csreesowmya22
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 62

Process Synchronization

Chapter 6
Contents of Process Synchronization

• Background

• The Critical-Section Problem

• Peterson’s Solution

• Synchronization Hardware

• Mutex Locks

• Semaphores

• Classic Problems of Synchronization

• Monitors

• Synchronization Examples

• Alternative Approaches
Objectives

• To present the concept of process synchronization.

• To introduce the critical-section problem, whose solutions can


be used to ensure the consistency of shared data

• To present both software and hardware solutions of the critical-


section problem

• To examine several classical process-synchronization problems

• To explore several tools that are used to solve process


synchronization problems
Background
• Processes can execute concurrently
– May be interrupted at any time, partially completing execution

• Concurrent access to shared data may result in data inconsistency

• Maintaining data consistency requires mechanisms to ensure the orderly


execution of cooperating processes

• Illustration of the problem:


Suppose that we wanted to provide a solution to the consumer-producer
problem that fills all the buffers. We can do so by having an integer counter
that keeps track of the number of full buffers. Initially, counter is set to 0.
It is incremented by the producer after it produces a new buffer and is
decremented by the consumer after it consumes a buffer.
Virtual memory view 5
2
5
• During execution, each process can only view its
4
virtual addresses, 3
• It cannot 3
– View another processes virtual address space 1
– Determine the physical address mapping 6
1
Virtual memory map Virtual memory map
Executing
process k
6 6 e
5 5 r
4 4 n
e
3 3 l
2 2
1 1
Virtual memory view
5
• During execution, each process can only view its
2
virtual addresses,
5
• It cannot 4
– View another processes virtual address space 3
– Determine the physical address mapping 3
1
Executing 6
process 1
Virtual memory map

k
6 e
5 r
4 n
e
3 l
2
1
Virtual memory view
5
• During execution, each process can only view its 2
virtual addresses 5
4
• It cannot
3
– View another processes virtual address space
3
– Determine the physical address mapping
1
Executing 6
process 1
Virtual memory map

k
6 e
5 r
4 n
e
3 l
2
1
Inter Process Communication

• Advantages of Inter Process Communication


– Information sharing
– Modularity

• Three ways
– Shared memory
– Message Passing

– Signals
Shared Memory
User Space
• One process will create an area in RAM which the
other process can access
Process 1
• Both processes can access shared memory like a
regular working memory
– Reading/writing is like regular reading/writing Shared
– Fast Memory

• Limitation : Error prone.


Needs synchronization between Process 2
processes
Message Passing
User Space

• Shared memory created in the kernel

• System calls such as send and receive used for Process 1


communication
– Cooperative : Each send must have a receive

• Advantage: Explicit sharing and less Process 2


error prone
• Limitation: slow.
Kernel

Shared
Memory
Introduction to Synchronization
Introduction to Synchronization

shared variable

int counter=5;
Program 1
Program 2
{ {
. .
. .
counter++ counter- -
. .
} }

What is the value of counter?


- expected to be 5
- but could also be 4 and 6
Introduction to Synchronization

shared variable

int counter=5;
Program 1
Program 2
{ {
. .
. .
counter++ counter- -
. .
} }

User program code System code


register counter
counter ++ register  register + 1
counter  register
shared variable

int counter=5;
Program 1 Program 2

{ {
. .
. .
counter ++ counter - -
. .
} }

R1  counter
R1  R1+1
counter  R1
context ----------------------
switch R2  counter
R2  R2 - 1
counter  R2

counter =5
shared variable

int counter=5;
Program 1 Program 2

{ {
. .
. .
counter++ counter- -
. .
} }

R1  counter
R1  counter
---------------------
R1  R1+1
R2  counter
counter  R1
context R2  R2 - 1
----------------------
switch counter  R2
R2  counter
----------------------
R2  R2 - 1
R1  R1+1
counter  R2
counter  R1
counter =5 counter =6
shared variable
int counter=5;
Program 1 Program 2

{ {
. .
. .
counter++ counter- -
. .
} }

R1  counter R2  counter
R1  counter ---------------------- ----------------------
R1  R1+1 R2  counter R1  counter
counter  R1 R2  R2 - 1 R1  R1+1
context ----------------------
switch R2  counter counter  R2 counter  R1
---------------------- ----------------------
R2  R2 - 1 R1  R1+1 R2  R2 - 1
counter  R2 counter  R1 counter  R2

counter =5 counter =6 counter =4


Race conditions
• A situation where several processes access and manipulate
the same data (critical section)
• The outcome depends on the order in which of access take place
• Prevent race condition by process synchronization
– Ensure only one process at a time manipulate the critical section

{
.
.
counter++ Critical section
.
}
Critical Section Problem

• Consider system of n processes {p0, p1, … pn-1}

• Each process has critical section segment of code


– Process may be changing common variables, updating table,
writing file, etc
– When one process in critical section, no other may be in its
critical section

• Critical section problem is to design protocol to solve this

• Each process must ask permission to enter critical section in


entry section, may follow critical section with exit section, then
remainder section
Critical Section
General structure of process Pi

do

{ entry section

critical section
exit section

remainder section

} while(true);
Shared variable
Locks and Unlocks int counter=5;
lock_t L;

Program 1 Program 2
{ {
* *
* *
Lock(L) Lock(L)
counter ++ counter --
Unlock(L) Unlock(L)
* *
} }

Lock(L) : acquire lock L exclusively


only the process with L can access the critical section
Unlock(L) : release exclusive access to lock L
permitting other processes to access the critical section
Solution to Critical-Section Problem

1. Mutual Exclusion – No more than one process in critical section at a given


time

2. Progress – when no process is in the critical section, any process that


request entry into the critical section must be permitted without any delay

3. No starvation (Bounded Wait)- There is an upper bound on the number of


times a process enters the critical section, while another is waiting.
Software Solution Shared
(attempt 1) int turn=1;

Process 1 Process 2

while(1){ while(1){
while(turn==2); //lock while(turn==1); //lock
critical section critical section
turn=2; //unlock turn=1; //unlock
Other code Other code
} }

• Achieves mutual exclusion

• Busy waiting- waste of power and time


• Needs to alternate execution in critical section
• Process1 -> process2 -> process1 -> process2
Software Solution (attempt 2)
Shared
int p1_inside=false, p2_inside=false;

Process 1 Process 2
while(1){ while(1){
while(p2_inside==true); //lock while(p1_inside==true); //lock
p1_inside=true p2_inside=true
critical section critical section
p1_inside=false; //unlock p2_inside=false; //unlock
other code other code
} }

• Need not alternate execution in critical section

• Does not guarantee mutual exclusion


Software Solution (attempt 2) : No mutual exclusion

CPU p1_inside p2_inside


while(p2_inside==true); false false
Context switch
while(p1_inside==true); false false
p2_inside=true false true
Context switch
p1_inside=true true true

Process 1 Process 2
while(1){ while(1){
while(p2_inside==true); //lock while(p1_inside==true); //lock
p1_inside=true ; p2_inside=true ;
critical section ; critical section ;
p1_inside=false; //unlock p2_inside=false; //unlock
other code other code
} }
Software solution (attempt 3)
Shared variable p2_wants_to_enter, p1_wants_to_enter

//PROCESS 1 //PROCESS 2
while(1){ while(1){
p1_wants_to_enter=true; p2_wants_to_enter=true;
while(p2_wants_to_enter=true); while(p1_wants_to_enter=true);
critical section; critical section;
p1_wants_to_enter=false; p2_wants_to_enter=false;
other code other code
} }

1. Achieves mutual exclusion


2. Does not achieve progress (could deadlock)
Software solution (attempt 3) : Endless wait

CPU P1_wants_to_enter P1_wants_to_enter


P1_wants_to_enter = true false true
Context switch
P2_wants_to_enter = true true true

Both processes (p1 and p2) will loop infinitely

Endless wait : each process is waiting for the other this is a deadlock
Peterson’s Solution

Software solution
for
critical section problem

Solve critical section problem for two processes

Prof. Chester Rebeiro, Dept. CSE, II


T Madras
Locks and Unlocks
Shared variable
int counter=5;
Lock_v L;
Process 1 Process 2
{ {
. .
. .
Lock(L); Lock(L);

counter++; counter--;

Unlock(L); Unlock(L);
. .
. .
} }

Lock(L) : acquire lock L exclusively


only the process with L can access the critical section
Unlock(L) : release exclusive access to lock L
permitting other process to access the critical section
Prof. Chester Rebeiro, Dept. CSE, II
T Madras
Peterson’s Solution
Globally defined
P2_wants_to_enter, P1_wants_to_enter, favored;

Process 1
While(1){

P1_wants_to_enter=true, favored=2;

while(P2_wants_to_enter AND favored=2);

critical section

P1_wants_to_enter=false;

other codes

}
Prof. Chester Rebeiro, Dept. CSE, II
T Madras
Peterson’s Solution Globally defined
P2_wants_to_enter, P1_wants_to_enter, favored;

Process 1 Process 2
While(1){ While(1){
P1_wants_to_enter=true, favored=2; P2_wants_to_enter=true, favored=1;

while(P2_wants_to_enter AND favored=2); while(P1_wants_to_enter AND favored=1);

critical section critical section

P1_wants_to_enter=false; P2_wants_to_enter=false;

other codes other codes


} }

Prof. Chester Rebeiro, Dept. CSE, II


T Madras
Peterson’s Solution
• Achieves mutual exclusion

• Deadlock can broken because favored can only be 1 or 2


– Therefore tie is broken only one process will enter the
critical section

• Solve critical section problem for two processes

Prof. Chester Rebeiro, Dept. CSE, II


T Madras
Hardware Locks

• Analyze Lock and unlock

• Hardware support: Test and Set instruction

• Intel Hardware support : xchg Instruction


Analyze lock and unlock
Does this scheme provide mutual exclusion?

lock=0

Process 1 Process 2
while(1){ while(1){

while(lock != 0); while(lock != 0);


lock=1;//lock lock=1;//lock
critical section critical section
lock=0;//unlock lock=0;//unlock

other codes other codes


} }
Does this scheme provide mutual exclusion? Answer : NO

Lock=0
Process 1 Process 2
while(1){ while(1){
Analyze lock and unlock

while(Lock != 0); while(Lock != 0);


Lock=1;//lock Lock=1;//lock
critical section critical section
Lock=0;//unlock Lock=0;//unlock
other codes other codes
} }

Lock-=0;
P1: while(Lock != 0);
----------------------------------- context switch
P2: while(Lock != 0);
P2: Lock=1;
----------------------------------- context switch
P1:Lock=1;
…….Both processes in critical section
We would make this operation atomic
Process 1
while(1){ Make Atomic

while(lock != 0);
lock=1;//lock

critical section
lock=0;//unlock

other codes
}
Hardware support
Test & Set Instruction

Write to a memory location, return its old value

int test_and_set(int * L){


int prev = *L;
*L=1;
processor 0
return prev;
}

Equivalent software representation L


(the entire function is executed atomically)
register
Hardware support
Test & Set Instruction

Write to a memory location, return its old value

int test_and_set(int * L){


int prev = *L;
*L=1;
processor 1
return prev;
}
0
Equivalent software representation L
(the entire function is executed atomically)
register
Hardware support
Test & Set Instruction

Write to a memory location, return its old value

int test_and_set(int * L){


int prev = *L;
*L=1;
processor 1
return prev;
}
0

Equivalent software representation L


(the entire function is executed atomically)

Why does this work? If two CPUs execute test_and_set at the


same time, the hardware ensures that one test_and_set both its
steps before the other starts.
Hardware support : Test & Set Instruction

Write to a memory location, return its old value

int test_and_set(int * L){ while(1){


int prev = *L; while(test_and_set(&Lock)==1);
*L=1; critical section
return prev; Lock=0;
} other codes
}
Equivalent software representation
(the entire function is executed atomically)

Why does this work? If two CPUs execute test_and_set at the same time, the
hardware ensures that one test_and_set both its steps before the other starts.

So the first invocation of test_and_set will read a 0 and set Lock


to 1 and return. The second test_and_set invocation will then
see Lock as 1, and will loop continuously until Lock becomes 0.
Intel Hardware support
(xchg Instruction)
Write to a memory location, return its old value

Processor 1 memory
10
int xchg((int * L, int V){
30
int prev = *L;
*L=V;
return prev; Processor 2
} 20

Equivalent software representation


(the entire function is executed atomically)

Why does this work? If two CPUs execute xchg at the same time,
the hardware ensures that one xchg completes, only then second
xchg starts.
Intel Hardware support : (xchg Instruction)

Note : %eax is returned


int xchg (addr, value){
%eax=value
Typical usage
xchg %eax, (addr)
xchg reg, mem
}

void acquire ( int *locked){


while(1){
Processor 1 if(xchg (locked, 1) == 0)
memory
10 break;
}
30 }

Processor 2 void release (int *locked){


20 locked = 0;
}
High level construct
• Spinlock
• Mutex
• semaphore
Spinlock usage

Process 1
int xchg (addr, value){
acquire(&locked)
%eax=value
critical section
xchg %eax, (addr)
release (&locked)
}

Process 2 void acquire ( int *locked){


while(1){
acquire(&locked) if(xchg (locked, 1) == 0)
critical section break;
release (&locked) }
}

• One process will acquire the lock void release (int *locked){
locked = 0;
• The other will wait in a loop repeatedly
}
checkering if the lock is available
• The lock becomes available when the
former process releases it
Issues with spinlock

 No compiler optimizations should be allowed

 Should not reorder memory loads and stores


More Issues with Spinlock : xchg %eax, X

CPU1 CPU2

Cache Coherence
L1 cache Protocol L1 cache

LOCK

memory
X

No caching of (X) possible. All xchg operations are bus transactions.


CPU asserts the LOCK, to inform that there is a ‘locked’ memory access

Acquire function in spinlock invokes xchg in a loop…each operation is a bus transaction


huge performance hits
Spinlock
(When should it be used?)

 Characteristic : busy waiting


• Useful for short critical sections, where much CPU time is not waisted waiting
eg. To increment a counter, access an array element

 No useful, when the period of waiting is unpredictable or will take a long time
• eg. Not good to read page from disk.
• use mutex instead
Mutexes int xchg (addr, value){
%eax=value
xchg %eax, (addr)
}
• Can we do better than busy waiting?
void lock ( int *locked){
• If critical section is locked then yield CPU while(1){
• Go to a SLEEP state if(xchg (locked, 1) == 0)
break;
• While unlocking, wakeup sleeping process else
sleep();
}
}

void unlock (int *locked){


locked = 0;
wakeup();
}
Issues in Mutex
(Thundering herd problem)
• A large number of processes wakeup( almost simultaneously)
when the event occurs.

• All waiting processes wakeup

• Leading to several context switches

• All processes go back to sleep state except for one, which


gets the critical section
• Large number of context switches
• Could lead to starvation
Solution : Thundering herd problem
int xchg (addr, value){
%eax=value
xchg %eax, (addr)
}
The solution
void lock ( int *locked){
• When entering critical section, push while(1){
into a queue before blocking if(xchg (locked, 1) == 0)
break;
• When exiting critical section, else
wakeup only the first process in the // add this process to queue
queue sleep();
}
}

void unlock (int *locked){


locked = 0;
//remove process P from queue
wakeup();
}
Semaphore
• Synchronization tool that provides more sophisticated ways (than Mutex locks) for
process to synchronize their activities.
• Semaphore S – integer variable
• Can only be accessed via two indivisible (atomic) operations

– wait() and signal()


• Originally called P() and V()

• Definition of the wait() operation


wait(S) {
while (S <= 0)
; // busy wait
S--;
}
• Definition of the signal() operation
signal(S) {
S++;
}
Semaphore Usage
• Counting semaphore – integer value can range over an unrestricted domain

• Binary semaphore – integer value can range only between 0 and 1


– Same as a mutex lock

• Can solve various synchronization problems

• Consider P1 and P2 that require S1 to happen before S2

Create a semaphore “synch” initialized to 0


P1:
S1;
signal(synch);
P2:
wait(synch);
S2;

• Can implement a counting semaphore S as a binary semaphore


Semaphore Implementation

• Must guarantee that no two processes can execute the wait()


and signal() on the same semaphore at the same time

• Thus, the implementation becomes the critical section


problem where the wait and signal code are placed in the
critical section
– Could now have busy waiting in critical section implementation
• But implementation code is short
• Little busy waiting if critical section rarely occupied

• Note that applications may spend lots of time in critical


sections and therefore this is not a good solution
Classical Problems of Synchronization

• Classical problems used to test newly-


proposed synchronization schemes
– Dining-Philosophers Problem
Dining-Philosophers Problem

• Philosophers spend their lives alternating thinking and eating


• Don’t interact with their neighbors, occasionally try to pick up 2 chopsticks
(one at a time) to eat from bowl
– Need both to eat, then release both when done
• In the case of 5 philosophers
– Shared data
• Bowl of rice (data set)
• Semaphore chopstick [5] initialized to 1
Dining-Philosophers Problem Algorithm

• The structure of Philosopher i:


do {
wait (chopstick[i] );
wait (chopStick[ (i + 1) % 5] );

// eat

signal (chopstick[i] );
signal (chopstick[ (i + 1) % 5] );

// think

} while (TRUE);

• What is the problem with this algorithm?


Dining-Philosophers Problem Algorithm (Cont.)

• Deadlock handling
– Allow at most 4 philosophers to be sitting
simultaneously at the table.
– Allow a philosopher to pick up the forks
only if both are available (picking must be
done in a critical section.
– Use an asymmetric solution -- an odd-
numbered philosopher picks up first the left
chopstick and then the right chopstick. Even-
numbered philosopher picks up first the
right chopstick and then the left chopstick.
Problems with Semaphores

• Incorrect use of semaphore operations:

– signal (mutex) …. wait (mutex)

– wait (mutex) … wait (mutex)

– Omitting of wait (mutex) or signal


(mutex) (or both)

• Deadlock and starvation are possible.


Monitors
• A high-level abstraction that provides a convenient and effective mechanism for
process synchronization

• Abstract data type, internal variables only accessible by code within the procedure

• Only one process may be active within the monitor at a time

• But not powerful enough to model some synchronization schemes


monitor monitor-name
{
// shared variable declarations
procedure P1 (…) { …. }

procedure Pn (…) {……}

Initialization code (…) { … }


}
}
Schematic view of a Monitor
Producer

while (true) {
/* produce an item in next produced */

while (counter == BUFFER_SIZE) ;


/* do nothing */
buffer[in] = next_produced;
in = (in + 1) % BUFFER_SIZE;
counter++;
}
Consumer

while (true) {
while (counter == 0)
; /* do nothing */
next_consumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;
/* consume the item in next consumed */
}
Reference
Prof. Chester Rebeiro,
Dept. CSE, IIT Madras

You might also like