Presentation is loading. Please wait.

Presentation is loading. Please wait.

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.

Similar presentations


Presentation on theme: "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."— Presentation transcript:

1 Synchronization Principles

2 Race Conditions

3 Race Conditions: An Example...... spooler directory 4 5 6 7 8 out in 4 7 somefile.txt list.c scores.txt Process A Process B (next job to print) (next available slot in queue) Global Variables

4 ...... spooler directory 4 5 6 7 8 out in 4 7 somefile.txt list.c scores.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 the next available slot in the spooler directory. Then it gets swapped out. Global Variables 77

5 ...... spooler directory 4 5 6 7 8 out in 4 7 somefile.txt list.c scores.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 the spooler directory and stores the path to the file there. Then it gets swapped out. Global Variables 7 7 b_file.txt

6 ...... spooler directory 4 5 6 7 8 out in 4 7 somefile.txt list.c scores.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 spooler directory. It stores the path to it’s file there... Global Variables 7 7 a_file.txt b_file.txt

7 ...... spooler directory 4 5 6 7 8 out in 7 12 a_file.txt Process A Process B (next to print) (next available slot) Eventually, the spooler prints the file pointed to by entry 7 in the spooler directory. User A gets their printout. User B has no clue what happened.

8 Critical Regions One way to address the problem of race conditions is to make sure that while one program is using a shared variable or 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 accessed is called a critical region. If we could guarantee that two programs were not both executing their critical regions at the same time, we could avoid race conditions.

9 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.

10 Solving the Spooler Problem Using Critical Regions

11 Process A Process B Process A enters its critical region Process A leaves its critical region Process A is swapped out. Process B attempts to enter its critical region Blocked Process B enters its critical region

12 High Level Language Statements are not atomic! Process A Process B shared variable “balance” balance = balance + amount; balance = balance - amount; loadr1, balance loadr2, amount addr1, r2 storer1, balance loadr1, balance loadr2, amount subr1, r2 storer1, balance r1 balance a balance new balance a restore the registers

13 Achieving Mutual Exclusion Disabling Interrupts Lock Variables Strict Alternation Petersen’s Solution The TSL Instruction with busy waiting

14 Disabling Interrupts Let process A disable interrupts just as it enters its critical section. Now it can examine and update shared resources without 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, but for some reason never enables them again? It is okay for the kernel to disable interrupts, but not for a user program to do so.

15 Lock 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.

16 Lock 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 a context switch occurs here?

17 Strict Alternation Again, use a single shared variable as a lock variable. However, this time we allow process A to enter only when the value of the lock is 0 and process B can enter only when the lock is 1.

18 Process A Process B Process A checks the lock variable. It is 0, so it enters its critical region lock variable 0

19 Process A Process B Process A checks the lock variable. It is 0, so it enters its critical region lock variable 0 Process B checks the lock variable. It is 0, so it cannot enter its critical region. It loops, waiting for the lock to change to 1. busy wait

20 Process A Process B Process A exits its critical region and changes the lock to 1. lock variable 1 busy wait Process B notices that the lock is now set to 1 and enters its critical region.

21 Process A Process B lock variable 0 busy wait When it leaves its critical region, process B changes to lock 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 critical section and B never executes it’s critical section, the lock never gets set back to 0!

22 Petersen’s Solution Consider 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 it gets the lock Processes indicate an interest in entering their shared region by calling this function. The parameter is either process 1 or 0 All values initially zero Process calls this function when it leaves its critical region.

23 Process 0 Process 1 Process 0 calls enter_region(0) lock 0 interested[0] 0 interested[1] 0

24 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); }

25 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

26 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 process 0 has set interested[0] to 1, process 1 cannot enter its critical region!

27 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

28 Process 0 Process 1 Since interested[1] = 0, the while executes once and the function exits immediately. Process 0 is now in 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 process 1 were in its critical region, interested[1] would be 1 and process 0 would be blocked from entering its critical region.

29 Process 0 Process 1 Process 1 calls enter_region(1) lock 0 interested[0] 1 interested[1] 0

30 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 ?

31 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

32 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

33 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

34 Process 0 Process 1 The process stays in this loop until 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

35 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; }

36 Process 0 Process 1 Process 1 drops through the loop and exits. It now is 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

37 The 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.

38 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

39 Both Petersen’s Solution and the TSL instruction work, … but require busy waiting. * Wasteful of CPU time * Priority Inversion Problem

40 Process H Process L Priority Inversion Problem Process H has high priority. The scheduling algorithm guarantees that it will always be run next if it is in a ready state.

41 Process H Process L Process H blocks, waiting for some I/O.

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

43 Process H Process L I/O completes and process H unblocks

44 Process H Process L Process H tries to enter its critical region. It calls enter_region and loops until lock is set to 0 by Process L

45 Process H Process L Because process H has a high priority, it gets all of 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 its critical region. The lock never clears.

46 Consumer-Producer Problems Fixed Size (bounded) buffer Producer Consumer Consumer-Producer problems are very common in system code.

47 Fixed Size buffer Producer Consumer The producer blocks if the buffer is full The consumer blocks if the buffer is empty. count A count is required so each can test the buffer condition.

48 Fixed Size buffer Producer Consumer if count == 0 block else remove item and decrement count if producer is asleep (blocked) wake producer if count == max block else add item and increment count if consumer is asleep (blocked) wake consumer count

49 Race Condition Fixed Size buffer Producer Consumer if count == 0 block else remove item and decrement count if producer is asleep wake producer if count == max block else add item and increment count if consumer is asleep wake consumer 0 1 The consumer does not get a chance to block. It gets swapped out.

50 Fixed Size buffer Producer Consumer if count == 0 block else remove item & decrement count if producer is asleep wake producer if count == max block else add item & increment count if consumer is asleep wake consumer 1 Since count was == 0, the producer thinks that the consumer is asleep, so it sends a wake up signal.

51 Fixed Size buffer Producer Consumer if count == 0 block else remove item and decrement count if producer is asleep wake producer if count == max block else add item and increment count if consumer is asleep wake consumer 1 The consumer is not really asleep. It has just been swapped out. Therefore, the wake-up signal is ignored. W a k e U p ! !

52 Fixed Size buffer Producer Consumer if count == 0 block else remove item & decrement count if producer is asleep wake producer if count == max block else add item & increment count if consumer is asleep wake consumer 1 The consumer is swapped into memory. The next instruction blocks. Now it waits for a wake up call.

53 Fixed Size buffer Producer Consumer if count == 0 block else remove item & decrement count if producer is asleep wake producer if count == max block else add item & increment count if consumer is asleep wake consumer 2 The next time the producer gets a time slice it stores a new element in the buffer. It thinks that the consumer is awake (count is non-zero), so no wake-up signal is ever sent.

54 Fixed Size buffer Producer Consumer if count == 0 block else remove item & decrement count if producer is asleep wake producer if count == max block else add item & increment count if consumer is asleep wake consumer max Eventually the buffer fills. The producer blocks. There is no way to wake the consumer. The program stops running.

55 Fixed Size buffer Producer Consumer if count == 0 block else remove item & decrement count if producer is asleep wake producer if count == max block else add item & increment count if consumer is asleep wake consumer max We need another mechanism to synchronize the Producer and the Consumer!

56 SemaphoresSemaphores The notion of semaphores was introduced in 1965 By E. W. Dijkstra.

57 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.

58 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 processes These are sometimes called mutexes. Solve producer-consumer problems

59 Semaphores have two operations: down if value > 0 decrement semaphore else block An Atomic Operation! up increment semaphore if a blocked process is waiting wake the process An Atomic Operation! (wait) (signal)

60 How could we use counting semaphores to solve the producer-consumer problem?

61 Producer slots.down() // add item items.up() Consumer semaphore slots semaphore items items.down() // remove item slots.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

62 MutexesMutexes 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 can be in one of two states: locked and unlocked.

63 Next Time.... Using semaphores and mutexes in Unix!


Download ppt "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."

Similar presentations


Ads by Google