View
216
Download
1
Embed Size (px)
Citation preview
Synchronization Synchronization PrinciplesPrinciples
Synchronization Synchronization PrinciplesPrinciples
Race Conditions: An Race Conditions: An ExampleExample
Race Conditions: An Race Conditions: An ExampleExample
.
.
.
spoolerdirectory
45
67
8
out
in
4
7
somefile.txt
list.cscores.txt
Process A
Process B
(next job to print)
(next available slot in queue)
Global Variables
.
.
.
spoolerdirectory
45
67
8
out
in
4
7
somefile.txt
list.cscores.txt
Process A
Process B
(next to print)
(next available slot)
Process A gets a time slice.It does some work. Then it wants to print. It gets thenext available slot in the spooler directory. Then it getsswapped out.
Global Variables
77
.
.
.
spoolerdirectory
45
67
8
out
in
4
7
somefile.txt
list.cscores.txt
Process A
Process B
(next to print)
(next available slot)
Process B now gets a time slice.It also wants to print. It gets the next available slot in thespooler directory and storesthe path to the file there. Thenit gets swapped out.
Global Variables7
7
b_file.txt
.
.
.
spoolerdirectory
45
67
8
out
in
4
7
somefile.txt
list.cscores.txt
Process A
Process B
(next to print)
(next available slot)
Process A now gets a time slice.It has what it believes is the next available slot in the spoolerdirectory. It stores the path to it’sfile there...
Global Variables7
7
a_file.txt
b_file.txt
.
.
.
spoolerdirectory
45
67
8
out
in
7
12a_file.txt
Process A
Process B
(next to print)
(next available slot)
Eventually, the spooler printsthe file pointed to by entry 7in the spooler directory. User Agets their printout. User B hasno clue what happened.
Critical RegionsCritical RegionsCritical RegionsCritical Regions
One way to address the problem of race conditions is tomake sure that while one program is using a shared variableor a shared file, other programs are excluded from doing so.This is called mutual exclusion.
The part of a program where a shared resource is accessedis called a critical region.
If we could guarantee that two programs were not bothexecuting their critical regions at the same time, we couldavoid race conditions.
The following four conditions must hold to avoid a race condition:
* No two processes may be simultaneously inside their critical regions
* No assumptions may be made about speeds, scheduling, or the number of CPUs
* No process running outside of its critical region may block another process
* No process should have to wait forever to enter its critical region.
Process A
Process B
Process A entersits critical region
Process A leavesits critical region
Process A is swapped out.Process B attemptsto enter its criticalregion
Blocked
Process B enters itscritical region
High Level Language Statements arenot atomic!
Process A Process B
shared variable “balance”
balance = balance + amount; balance = balance - amount;
load r1, balanceload r2, amountadd r1, r2store r1, balance
load r1, balanceload r2, amountsub r1, r2store r1, balance
r1 balanceabalancenewbalancea
restore the registers
Achieving Mutual Achieving Mutual ExclusionExclusion
Achieving Mutual Achieving Mutual ExclusionExclusion
Disabling Interrupts
Lock Variables
Strict Alternation
Petersen’s Solution
The TSL Instruction
with busy waiting
Disabling InterruptsDisabling InterruptsDisabling InterruptsDisabling InterruptsLet process A disable interrupts just as it enters its criticalsection. Now it can examine and update shared resourceswithout concern. The timer interrupt won’t be caught until interrupts are enabled again. Process A then enables interrupts as it leaves its critical section.
Problem: What if a user program disables interrupts, butfor some reason never enables them again?
It is okay for the kernel to disable interrupts, but notfor a user program to do so.
Lock VariablesLock VariablesLock VariablesLock Variables
Consider having a single shared variable that all processes use to test whether or not they can enter their critical section. If the value of the lock is 0, a process sets it to 1 and enters its critical region. If it is 1, it waits until the lock becomes 0.
Lock VariablesLock VariablesLock VariablesLock Variables
Consider having a single shared variable that all processes use to test whether or not they can enter their critical section. If the value of the lock is 0, a process sets it to 1 and enters its critical region. If it is 1, it waits until the lock becomes 0.
while (lock == 1);lock = 1;// critical region . . .
what happens if acontext switch occurshere?
Strict AlternationStrict AlternationStrict AlternationStrict Alternation
Again, use a single shared variable as a lock variable.However, this time we allow process A to enter onlywhen the value of the lock is 0 and process B can enteronly when the lock is 1.
Process A
Process B
Process A checks the lockvariable. It is 0, so it entersits critical region
lock variable
0
Process A
Process B
Process A checks the lockvariable. It is 0, so it entersits critical region
lock variable
0
Process B checks the lockvariable. It is 0, so it cannotenter its critical region. Itloops, waiting for the lock tochange to 1.
busy wait
Process A
Process B
Process A exits its criticalregion and changes the lock to 1.
lock variable
1
busy wait
Process B notices that thelock is now set to 1 and entersits critical region.
Process A
Process B
lock variable
0
busy wait
When it leaves its criticalregion, process B changes tolock to 0.
What are the problems here?
Busy waiting (a spin lock) wastes CPU time
Processes must alternate.
Recall that process A can enter only when the value of the lock is 0. If A leaves it’s criticalsection and B never executes it’s critical section,the lock never gets set back to 0!
Petersen’s SolutionPetersen’s SolutionPetersen’s SolutionPetersen’s SolutionConsider the following code:
#define N 2
int lock;int interested[N];
void enter_region(int process){ int other; other = 1 – process; // flips it interested[process] = 1; lock = process; while (lock == process && interested[other] == 1);}
void leave_region(int process){ interested[process] = 0;}
Each process stores its number here when itgets the lock
Processes indicate an interest inentering their shared region bycalling this function. The parameteris either process 1 or 0
All values initially zero
Process calls this functionwhen it leaves its criticalregion.
Process 0
Process 1
lock 0
interested[0] 0
interested[1] 0
other ?
void enter_region(int process){ int other; other = 1 – process; interested[process] = 1; lock = process; while (lock == process && interested[other] == 1);}
Process 0
Process 1
lock 0
interested[0] 0
interested[1] 0
void enter_region(int process){ int other; other = 1 – process; // if I’m 0 the other process is 1 interested[process] = 1; lock = process; while (lock == process && interested[other] == 1);}
other 1
Process 0
Process 1
lock 0
interested[0] 1
interested[1] 0
void enter_region(int process){ int other; other = 1 – process; interested[process] = 1; // Mark me as interested lock = process; while (lock == process && interested[other] == 1);}
other 1
Note: Once process0 hasset interested[0] to 1, process1 cannot enter itscritical region!
Process 0
Process 1
lock 0
interested[0] 1
interested[1] 0
void enter_region(int process){ int other; other = 1 – process; interested[process] = 1; lock = process; // give me the lock while (lock == process && interested[other] == 1);}
other 1
Process 0
Process 1
Since interested[1] = 0, the whileexecutes once and the functionexits immediately. Process 0 is nowin its critical region.
lock 0
interested[0] 1
interested[1] 0
void enter_region(int process){ int other; other = 1 – process; interested[process] = 1; lock = process; while (lock == process && interested[other] == 1);}
other 1
Note: if process1 were in its criticalregion, interested[1] would be 1 andprocess0 would be blocked from entering its critical region.
Process 0
Process 1
lock 0
interested[0] 1
interested[1] 0
void enter_region(int process){ int other; other = 1 – process; interested[process] = 1; lock = process; while (lock == process && interested[other] == 1);}
other ?
Process 0
Process 1
lock 0
interested[0] 1
interested[1] 0
void enter_region(int process){ int other; other = 1 – process; // I’m 1 so other is 0 interested[process] = 1; lock = process; while (lock == process && interested[other] == 1);}
other 0
0
Process 0
Process 1
lock 0
interested[0] 1
interested[1] 1
void enter_region(int process){ int other; other = 1 – process; interested[process] = 1; // mark me as interested lock = process; while (lock == process && interested[other] == 1);}
other 0
0
Process 0
Process 1
lock 1
interested[0] 1
interested[1] 1
void enter_region(int process){ int other; other = 1 – process; interested[process] = 1; lock = process; // give me the lock while (lock == process && interested[other] == 1);}
other 0
Process 0
Process 1
The process stays in this loopuntil interested[0] changes to 0.
lock 1
interested[0] 1
interested[1] 1
void enter_region(int process){ int other; other = 1 – process; interested[process] = 1; lock = process; while (lock == process && interested[other] == 1);}
other 0
Process 0
Process 1
Process 0 calls leave_region(0)
lock 1
interested[0] 0
interested[1] 1
void leave_region(int process){ interested[process] = 0;}
Process 0
Process 1
Process 1 drops throughthe loop and exits. It nowis in its critical region.
lock 1
interested[0] 0
interested[1] 1
void enter_region(int process){ int other; other = 1 – process; interested[process] = 1; lock = process; while (lock == process && interested[other] == 1);}
other 0
The TSL InstructionThe TSL InstructionThe TSL InstructionThe TSL Instruction
Many computers have an instruction of the form
tsl rx, lock
The instruction does two things: * It stores the current value of lock in the register rx * It stores a non-zero value in lock
The key is that this instruction is guaranteed to be atomic, that is, no other instruction can be executed until both parts of the instruction are done.
Consider the following code in assembly language.
The lock must be zero to enter the critical section:
enter_region:
tsl r1, lock
cmp r1, #0
jne enter_region
ret
leave_region:
move lock, #0
ret
stores current value of lock in r1 and a non-zero value in lock
test to see if original value of lock was zero, Loop back to beginning of loop if not. If it is zero, drop out of the loop and return. The lock is now non-zero.
set the value of lock to 0
Both Petersen’s Solution and the TSL instruction work, … but require busy waiting.
* Wasteful of CPU time
* Priority Inversion Problem
Process H
Process L
Priority Inversion Priority Inversion ProblemProblem
Priority Inversion Priority Inversion ProblemProblem
Process H has high priority. The schedulingalgorithm guarantees that it will always be run next if it is in a ready state.
Process H
Process L
Process H tries to enter its critical region.It calls enter_region and loops until lockis set to 0 by Process L
Process H
Process L
Because process H has a high priority, it gets allof the cpu time. It continues to loop,waiting for the lock to turn to 0.
Process L, because it has a low priority,never gets any cpu time it and so never exits itscritical region. The lock never clears.
Consumer-Producer Consumer-Producer ProblemsProblems
Consumer-Producer Consumer-Producer ProblemsProblems
FixedSize
(bounded)buffer
Producer
Consumer
Consumer-Producer problemsare very common in system code.
FixedSize
buffer
Producer
Consumer
The producer blocksif the buffer is full
The consumer blocksif the buffer is empty.
countA count is requiredso each can test thebuffer condition.
FixedSize
buffer
Producer
Consumer
if count == 0 blockelse remove item and decrement countif producer is asleep (blocked) wake producerif count == max
blockelse add item and increment countif consumer is asleep (blocked) wake consumer
count
Race ConditionRace ConditionRace ConditionRace Condition
FixedSize
buffer
Producer
Consumer
if count == 0 blockelse remove item and decrement countif producer is asleep wake producerif count == max
blockelse add item and increment countif consumer is asleep wake consumer
01
The consumer does notget a chance to block.It gets swapped out.
FixedSize
buffer
Producer
Consumer
if count == 0 blockelse remove item & decrement countif producer is asleep wake producerif count == max
blockelse add item & increment countif consumer is asleep wake consumer
1Since count was == 0,the producer thinks thatthe consumer is asleep, soit sends a wake up signal.
FixedSize
buffer
Producer
Consumer
if count == 0 blockelse remove item and decrement countif producer is asleep wake producerif count == max
blockelse add item and increment countif consumer is asleep wake consumer
1The consumer is not really asleep.It has just been swapped out.Therefore, the wake-up signalis ignored.
Wake Up! !
FixedSize
buffer
Producer
Consumer
if count == 0 blockelse remove item & decrement countif producer is asleep wake producerif count == max
blockelse add item & increment countif consumer is asleep wake consumer
1The consumer is swappedinto memory. The next instruction blocks. Now it waits for a wake up call.
FixedSize
buffer
Producer
Consumer
if count == 0 blockelse remove item & decrement countif producer is asleep wake producerif count == max
blockelse add item & increment countif consumer is asleep wake consumer
2
The next time the producergets a time slice it stores a newelement in the buffer. It thinksthat the consumer is awake (countis non-zero), so no wake-up signal is ever sent.
FixedSize
buffer
Producer
Consumer
if count == 0 blockelse remove item & decrement countif producer is asleep wake producerif count == max
blockelse add item & increment countif consumer is asleep wake consumer
max
Eventually the buffer fills. Theproducer blocks. There is noway to wake the consumer. Theprogram stops running.
FixedSize
buffer
Producer
Consumer
if count == 0 blockelse remove item & decrement countif producer is asleep wake producerif count == max
blockelse add item & increment countif consumer is asleep wake consumer
max
We need another mechanism to synchronize the Producer and the Consumer!
SemaphoresSemaphoresSemaphoresSemaphores
The notion of semaphores was introduced in 1965By E. W. Dijkstra.
Semaphores are a programming construct designed by E. W. Dijkstra in 1965. Dijkstra's model was the operation of railroads: consider a stretch of railroad in which there is a single track over which only one train at a time is allowed. Guarding this track is a semaphore. A train must wait before entering the single track until the semaphore is in a state that permits travel. When the train enters the track, the semaphore changes state to prevent other trains from entering the track. A train that is leaving this section of track must again change the state of the semaphore to allow another train to enter.
Counting Semaphore: Its values can range from 0 to some positive number
Binary Semaphore: Its values are 1 and 0
Solve critical section problems with multiple processesThese are sometimes called mutexes.
Solve producer-consumer problems
Semaphores have two operations:
downif value > 0 decrement semaphoreelse block
An Atomic Operation!
upincrement semaphoreif a blocked process is waiting wake the process
An Atomic Operation!
(wait)
(signal)
How could we use counting How could we use counting semaphores to solve the semaphores to solve the producer-consumer producer-consumer problem?problem?
How could we use counting How could we use counting semaphores to solve the semaphores to solve the producer-consumer producer-consumer problem?problem?
Producer
slots.down()// add itemitems.up()
Consumer
semaphore slotssemaphore items
items.down()// remove itemslots.up()
See the Unix Synchronization slides (slideSet20.ppt) for producer-consumer code written with Unix semaphores.
Value is number of empty slots available in the buffer
Value is number of items in the buffer
Will block if no empty slots are available Wakes up
the producer if the producer is blocked
MutexesMutexesMutexesMutexes
Binary Semaphores are also known as Mutexes.When the semaphore’s ability to count is not needed,a mutex can be used. A mutex is a variable that canbe in one of two states: locked and unlocked.