63
Synchronization Synchronization Principles Principles

Synchronization Principles. Race Conditions Race Conditions: An Example...... spooler directory 4 5 6 7 8 out in 4 7 somefile.txt list.c scores.txt Process

  • View
    216

  • Download
    1

Embed Size (px)

Citation preview

Synchronization Synchronization PrinciplesPrinciples

Synchronization Synchronization PrinciplesPrinciples

Race Conditions

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.

Solving the Spooler Problem UsingCritical Regions

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

Process 0 calls enter_region(0)

lock 0

interested[0] 0

interested[1] 0

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

Process 1 calls enter_region(1)

lock 0

interested[0] 1

interested[1] 0

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 blocks, waitingfor some I/O.

Process H

Process L

Process L now gets the cpu.It enters it’s critical region.

Process H

Process L

I/O completes and process H unblocks

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.

Next Time ....

Using semaphores and mutexes in Unix!