chapter 6 (a): synchronization

41
Silberschatz, Galvin and Gagne ©2007 ating System Concepts with Java – 7 th Edition, Nov 15, 2006 Chapter 6 (a): Synchronization

Upload: galen

Post on 05-Jan-2016

44 views

Category:

Documents


3 download

DESCRIPTION

Chapter 6 (a): Synchronization. Module 6: Process Synchronization. Background Producer/Consumer Again Race Conditions Scheduler Assumptions The Critical-Section Problem Critical Section Goals Deriving a Solution Peterson’s Algorithm Bakery Algorithm Hardware Support. Background. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Chapter 6 (a):  Synchronization

Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Chapter 6 (a): Synchronization

Page 2: Chapter 6 (a):  Synchronization

6.2 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Module 6: Process Synchronization

Background Producer/Consumer Again Race Conditions Scheduler Assumptions The Critical-Section Problem Critical Section Goals Deriving a Solution Peterson’s Algorithm Bakery Algorithm Hardware Support

Page 3: Chapter 6 (a):  Synchronization

6.3 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Background

Concurrent access to shared data may result in data inconsistency

Maintaining data consistency requires mechanisms to ensure the orderly execution of cooperating processes

Suppose that we wanted to provide a solution to the consumer-producer problem that fills all the buffers. Have an integer count that tracks the number of full

buffers. Initially, count is set to 0. Producer increments count after producing a buffer Consumer decrements after consuming a buffer

Page 4: Chapter 6 (a):  Synchronization

6.4 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Producer-Consumer

• Producer

while (true) { /* produce an item and */ /* put in nextProduced */

while (count == BUFFER_SIZE); // do nothing b/c full

buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++;

}

• Consumer

while (true) {

while (count == 0); // do nothing b/c

empty

nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--;

/* consume the item */ /* in nextConsumed */}

Page 5: Chapter 6 (a):  Synchronization

6.5 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Race Condition

count++ could be implemented as

register1 = count register1 = register1 + 1 count = register1

count-- could be implemented as

register2 = count register2 = register2 - 1 count = register2

Consider this execution interleaving with “count = 5” initially:S0: producer execute register1 = count {register1 = 5}S1: producer execute register1 = register1 + 1 {register1 = 6} S2: consumer execute register2 = count {register2 = 5} S3: consumer execute register2 = register2 - 1 {register2 = 4} S4: producer execute count = register1 {count = 6 } S5: consumer execute count = register2 {count = 4}

Page 6: Chapter 6 (a):  Synchronization

6.6 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

What happened?

Threads (and sometimes processes) share global memory

When a process contains multiple threads, they have Private registers and stack memory (the context

switching mechanism needs to save and restore registers when switching from thread to thread)

Shared access to the remainder of the process “state” This can result in race conditions

Page 7: Chapter 6 (a):  Synchronization

6.7 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Two threads, one counter

Popular web server Uses multiple threads to speed things up. Simple shared state error:

each thread increments a shared counter to track number of hits

What happens when two threads execute concurrently?

…hits = hits + 1;…

Page 8: Chapter 6 (a):  Synchronization

6.8 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Shared counters

Possible result: lost update!

One other possible result: everything works.

Difficult to debug Called a “race condition”

hits = 0 + 1

read hits (0)

hits = 0 + 1read hits (0)

T1 T2

hits = 1

hits = 0

time

Page 9: Chapter 6 (a):  Synchronization

6.9 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Race conditions

Def: a timing dependent error involving shared state Whether it happens depends on how threads scheduled In effect, once thread A starts doing something, it needs to

“race” to finish it because if thread B looks at the shared memory region before A is done, it may see something inconsistent

Hard to detect: All possible schedules (permutations) have to be safe

Number of possible schedule permutations is huge Some bad schedules? Some that will work sometimes?

Intermittent Unpredictable Timing dependent = small changes can hide bug

If a bug is deterministic and repeatable, celebrate!

Page 10: Chapter 6 (a):  Synchronization

6.10 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

If i is shared, and initialized to 0 Who wins? Is it guaranteed that someone wins? What if each thread runs on a separate, identical speed CPU?

executing in parallel

Scheduler Assumptions

Process b: while(i > -10)

i = i - 1; print “B won!”;

Process a: while(i < 10)

i = i +1; print “A won!”;

Page 11: Chapter 6 (a):  Synchronization

6.11 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Scheduler Assumptions

Normally we assume that A scheduler always gives every executable thread

opportunities to run In effect, each thread makes finite progress

But schedulers aren’t always fair Some threads may get more chances than others

To reason about worst case behavior we sometimes think of the scheduler as an adversary trying to “mess up” the algorithm

Page 12: Chapter 6 (a):  Synchronization

6.12 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Critical Section Problem

Problem: Design a protocol for processes to cooperate, such that only one process is in its critical section at any time How to make multiple instructions seem like one?

Processes progress with non-zero speed, no assumption on clock speed

Used extensively in operating systems:Queues, shared variables, interrupt handlers, etc.

Process 1

Process 2

CS1

Time

CS2

Page 13: Chapter 6 (a):  Synchronization

6.13 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Critical-Section Problem

1. Race Condition - When there is concurrent access to shared data and the final outcome depends upon order of execution.

2. Critical Section - Section of code where shared data is accessed.

3. Entry Section - Code that requests permission to enter its critical section.

4. Exit Section - Code that is run after exiting the critical section

Page 14: Chapter 6 (a):  Synchronization

6.14 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Critical Section Goals

Threads do some stuff but eventually might try to access shared data

CSEnter();Critical section

CSExit();

T1 T2time

CSEnter();Critical section

CSExit();

T1 T2

Page 15: Chapter 6 (a):  Synchronization

6.15 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Critical Section Goals

Perhaps they loop (perhaps not!)

T1 T2

CSEnter();Critical section

CSExit();

T1 T2

CSEnter();Critical section

CSExit();

Page 16: Chapter 6 (a):  Synchronization

6.16 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

We would like Safety (aka mutual exclusion)

No more than one thread can be in a critical section at any time. Liveness (aka progress)

A thread that is seeking to enter the critical section will eventually succeed

Bounded waiting A bound must exist on the number of times that other threads are

allowed to enter their critical sections after a thread has made a request to enter its critical section and before that request is granted

Assume that each process executes at a nonzero speed No assumption concerning relative speed of the N processes

Ideally we would like fairness as well If two threads are both trying to enter a critical section, they have equal

chances of success … in practice, fairness is rarely guaranteed

Critical Section Goals

Page 17: Chapter 6 (a):  Synchronization

6.17 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Solving the problem

CSEnter()

{

while(inside) continue;

inside = true;

}

A first idea: Have a boolean flag, inside. Initially false.

CSExit(){

inside = false;}

Now ask: Is this Safe? Live? Bounded waiting?

Code is not safe: thread 0 could finish the while test when inside is false, but then thread 1 might call CSEnter() before thread 0 can set

inside to true!

Page 18: Chapter 6 (a):  Synchronization

6.18 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Solving the problem: Take 2

CSEnter(int i)

{

inside[i] = true;

while(inside[j]) continue;

}

A different idea (assumes just two threads): Have a boolean flag, inside[i]. Initially false.

CSExit(int i){

inside[i] = false;}

Now ask: Is this Safe? Live? Bounded waiting?

Code isn’t live (doesn’t guarantee progress): with bad luck, both threads could be looping, with 0

looking at 1, and 1 looking at 0

Page 19: Chapter 6 (a):  Synchronization

6.19 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Solving the problem: Take 3

CSEnter(int i)

{

while(turn != i) continue;

}

Another broken solution, for two threads Have a turn variable, turn, initially 1.

CSExit(int i){

turn = i ^ 1;}

Now ask: Is this Safe? Live? Bounded waiting?

Code isn’t live: thread 1 can’t enter unless thread 0 did first, and vice-versa. But perhaps one thread needs to enter many times and the

other fewer times, or not at all

Page 20: Chapter 6 (a):  Synchronization

6.20 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Peterson’s Algorithm (1981)

CSEnter(int i){

inside[i] = true;turn = J;while(inside[J] && turn == J)

continue; }

CSExit(int i) {

inside[i] = false;}

Now ask: Is this Safe? Live? Bounded waiting?

Page 21: Chapter 6 (a):  Synchronization

6.21 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Peterson’s Solution

Two process solution Assume that the LOAD and STORE instructions

are atomic; that is, cannot be interrupted. The two processes share two variables:

int turn; Boolean inside[2]

The variable turn indicates whose turn it is to enter the critical section.

The inside array is used to indicate if a process is ready to enter the critical section. inside[i] = true implies that process Pi is ready!

Page 22: Chapter 6 (a):  Synchronization

6.22 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Safety (by contradiction): Assume that both processes (Alice and Bob) are in

their critical section (and thus have their inside flags set). Since only one, say Alice, can have the turn, the other (Bob) must have reached the while() test before Alice set her inside flag.

However, after setting his inside flag, Alice gave away the turn to Bob. Bob has already changed the turn and cannot change it again, contradicting our assumption.

Liveness & Bounded waiting => the turn variable.

Analyzing Peterson’s Algorithm

Page 23: Chapter 6 (a):  Synchronization

6.23 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Generalize to N Threads?

Obvious approach won’t work:

Issue: Who’s turn is next?

CSEnter(int i){

inside[i] = true;for(J = 0; J < N; J++)

while(inside[J] && turn == J)continue;

}

CSExit(int i){

inside[i] = false;}

Page 24: Chapter 6 (a):  Synchronization

6.24 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Bakery “concept”

Think of a popular store with a crowded counter, perhaps the cheese line at Zabar’s People take a ticket from a machine If nobody is waiting, tickets don’t matter When several people are waiting, ticket

order determines order in which they can make purchases

Page 25: Chapter 6 (a):  Synchronization

6.25 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Bakery Algorithm: “Take 1”

int ticket[n]; int next_ticket;

CSEnter(int i){

ticket[i] = ++next_ticket;for(J = 0; J < N; J++)

while(ticket[J] && ticket[J] < ticket[i])continue;

}

CSExit(int i){

ticket[i] = 0;}

Oops… access to next_ticket is a problem!

Page 26: Chapter 6 (a):  Synchronization

6.26 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Bakery Algorithm: “Take 2”

int ticket[n];

CSEnter(int i){

ticket[i] = max(ticket[0], … ticket[N-1])+1;for(J = 0; J < N; J++)

while(ticket[J] && ticket[j] < ticket[i])continue;

}

CSExit(int i){

ticket[i] = 0;}

Clever idea: just add one to the max.

Just add 1 to the max!

Oops… two could pick the same value!

Page 27: Chapter 6 (a):  Synchronization

6.27 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Bakery Algorithm: “Take 3”

If i, j pick same ticket value, id’s break tie:

(ticket[J] < ticket[i]) || (ticket[J]==ticket[i] && J<i)

Notation: (B,J) < (A,i) to simplify the code:

(B<A || (B==A && J<i)), e.g.:

(ticket[J],J) < (ticket[i],i)

Page 28: Chapter 6 (a):  Synchronization

6.28 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Bakery Algorithm: “Take 4”

int ticket[N]; boolean picking[N] = false;

CSEnter(int i){

ticket[i] = max(ticket[0], … ticket[N-1])+1;for(J = 0; J < N; J++)

while(ticket[J] && (ticket[J],J) < (ticket[i],i))

continue;}

CSExit(int i){

ticket[i] = 0;}

Oops… i could look at J when J is still storing its ticket, and yet J could have a lower id than me (i)!

Page 29: Chapter 6 (a):  Synchronization

6.29 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Bakery Algorithm: Almost final

int ticket[N]; boolean choosing[N] = false;

CSEnter(int i){

choosing[i] = true;ticket[i] = max(ticket[0], … ticket[N-1])+1;choosing[i] = false;for(J = 0; J < N; J++) {

while(choosing[J]) continue;while(ticket[J] && (ticket[J],J) < (ticket[i],i))

continue;

}}

CSExit(int i){

ticket[i] = 0;}

Page 30: Chapter 6 (a):  Synchronization

6.30 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Bakery Algorithm: Issues?

What if we don’t know how many threads might be running? The algorithm depends on having an agreed upon

value for N Somehow would need a way to adjust N when a

thread is created or one goes away Also, technically speaking, ticket can overflow!

Solution: Change code so that if ticket is “too big”, set it back to zero and try again.

Page 31: Chapter 6 (a):  Synchronization

6.31 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Bakery Algorithm: Final

int ticket[N]; /* Important: Disable thread scheduling when changing N */ boolean choosing[N] = false;

CSEnter(int i){

do { ticket[i] = 0; choosing[i] = true; ticket[i] = max(ticket[0], … ticket[N-1])+1; choosing[i] = false;} while(ticket[i] >= MAXIMUM);for(J = 0; J < N; J++) {

while(choosing[J]) continue;while(ticket[J] && (ticket[J],J) < (ticket[i],i))

continue;}

}

CSExit(int i){

ticket[i] = 0;}

Page 32: Chapter 6 (a):  Synchronization

6.32 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Approaches to Critical Sections

Everything we’ve seen so far is a software-only solution that relies on reads and writes being atomic Atomic = non-interruptible

Another approach: disable interrupts Disable interrupts briefly when calling CSEnter() and CSExit() Currently running code would execute without preemption Available only in the kernel (why?) Generally doesn’t work on multiprocessor systems Operating systems using this not broadly scalable

Modern machines provide hardware “help”: atomic instructions Either test memory word and set value (test and set) Or swap contents of two memory words (compare and swap)

Idea is to provide a mechanism for critical sections: a lock

Page 33: Chapter 6 (a):  Synchronization

6.33 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Critical Section Using Locks

Page 34: Chapter 6 (a):  Synchronization

6.34 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

TestAndSet Instruction

Definition:

boolean TestAndSet (boolean *target) { boolean rv = *target; *target = TRUE; return rv: }

Page 35: Chapter 6 (a):  Synchronization

6.35 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Solution using TestAndSet

Shared boolean variable lock., initialized to false. Solution:

while (true) { while ( TestAndSet (&lock )) ; /* do nothing

// critical section

lock = FALSE;

// remainder section }

Page 36: Chapter 6 (a):  Synchronization

6.36 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Critical Sections using TestAndSet

cs_enter:TSL REGISTER, LOCK // copy lock to reg and set to 1CMP REGISTER, #0 // was lock 0?JNE cs_enter // if so, loopRET // otherwise return, in critical sec

cs_exit:STORE LOCK #0 // set lock to 0RET

Page 37: Chapter 6 (a):  Synchronization

6.37 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Swap Instruction

Definition:

void Swap (boolean *a, boolean *b) { boolean temp = *a; *a = *b; *b = temp: }

Page 38: Chapter 6 (a):  Synchronization

6.38 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Shared Boolean variable lock initialized to FALSE; Each process has a local Boolean variable key.

Solution:

while (true) { key = TRUE; while ( key == TRUE) Swap (&lock, &key ); // critical section

lock = FALSE;

// remainder section }

Solution using Swap

Page 39: Chapter 6 (a):  Synchronization

6.39 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Critical Sections using Swap

cs_enter:MOVE REGISTER, #1 // put 1 in registerXCHG REGISTER, LOCK // swap reg and lock contentsCMP REGISTER, #0 // was lock zero?JNE cs_enter // if not, loopRET // otherwise return, in cs

cs_exit:MOVE LOCK, #0 // store a zero in lockRET // return to caller

Page 40: Chapter 6 (a):  Synchronization

6.40 Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

Providing Critical Sections to Users

Everything we’ve seen so far involves busy waiting Also known as spin locks Acceptable for short waits (e.g., interrupts) Need a general-purpose mechanism that allows

sleeping Would like to provide higher-level abstractions to users

CSEnter and CSExit are possibilities Operating systems have offer other primitives

E.g., semaphores, condition variables, mutexes Built out of low-level critical section operations More in next class

Page 41: Chapter 6 (a):  Synchronization

Silberschatz, Galvin and Gagne ©2007Operating System Concepts with Java – 7th Edition, Nov 15, 2006

End of Chapter 6 (a)