Presentation is loading. Please wait.

Presentation is loading. Please wait.

Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition Process/Thread Synchronization Modified from Chapter 6 for 170 with Nachos.

Similar presentations


Presentation on theme: "Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition Process/Thread Synchronization Modified from Chapter 6 for 170 with Nachos."— Presentation transcript:

1 Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition Process/Thread Synchronization Modified from Chapter 6 for 170 with Nachos threads, Tao Yang, Oct 2011

2 6.2 Topics The Critical-Section Problem & Solutions. Locks Semaphores Condition variables (monitors). Implementation Software solutions: Peterson’s Solution Synchronization Hardware Synchronization Examples

3 6.3 Objectives 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 introduce the concept of an atomic transaction and describe mechanisms to ensure atomicity

4 6.4 A. Frank - P. Weisberg Multiple Producers and Consumers

5 6.5 Background Maintain integer count that keeps track of the number of items to consume in the buffer. Initially, count 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. Concurrent access to shared data may result in data inconsistency Maintaining data consistency requires mechanisms to ensure the orderly execution of cooperating processes

6 6.6 Producer Code while (true) { while (count == BUFFER_SIZE) ; // do nothing buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; }

7 6.7 Consumer while (true) { while (count == 0) ; // do nothing nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; }

8 6.8 Definitions Race Conditions: two or more processes are reading and writing on shared data and the final result depends on who runs precisely when Mutual exclusion: making sure that if one process is accessing a shared memory, the other will be excluded from doing the same thing Critical region: the part of the program where shared variables are accessed

9 6.9 Race Conditions: Example Count-- Producer thread Consumer thread Count++ Count=5 Is count still 5?

10 6.10 Race Conditions: Example Count—: register2 = count register2 = register2 - 1 count = register2 Producer thread Consumer thread Count++: register1 = count register1 = register1 + 1 count = register1 Count=5 Is count still 5?

11 6.11 Race Conditions: Example Count—: register2 = count register2 = register2 - 1 count = register2 Producer thread Consumer thread Count++: register1 = count register1 = register1 + 1 count = register1 Count=5 Is count still 5?

12 6.12 Race Condition “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}

13 6.13 Property of Critical-Section Solutions 1. Mutual Exclusion – Only one can enter the critical section. 2. Progress - If some processes wish to enter their critical section and nobody is in the critical section, then one of them will enter in a limited time. 3. Bounded Waiting - If one process starts to wait for entering an critical section, there is a limit on the number of times other processes entering the section before this process enters.

14 6.14

15 6.15 Solution to Critical-section Problem acquire lock critical section release lock remainder section 1. Locks 2. Semaphore 3. Conditional Variables

16 6.16 Semaphore Semaphore S – integer variable Can only be accessed /modified via two indivisible (atomic) operations wait (S) { //also called P() while S <= 0 ; // wait S--; } signal (S) { //also called V() S++; }

17 6.17 Semaphore as General Synchronization Tool Counting semaphore – initial value representing how many threads can be in the critical section. Binary semaphore (also known as mutex locks) – integer value ranged between 0 and 1. Provides mutual exclusion Semaphore mutex; // initialized to 1 do { wait (mutex); // Critical Section signal (mutex); } while (TRUE);

18 6.18 Nachos Threads class Thread{ public: Thread (char *name); ~Thread(); void Fork( void (*Func)( int), int arg); void Yield(); void Finish(); }

19 6.19 Nachos Threads: Methods supported Thread(char *debugName). Create a thread. Fork(VoidFunctionPtr func, int arg). A thread starts to execute a function. Yield(). Suspend the calling thread and the system selects a new one for execution. Sleep(). Suspend the current thread, change its state to BLOCKED, and remove it from the ready list Finish()

20 6.20 main () { Thread *t1 = new Thread("forked thread1"); Thread *t2 = new Thread("forked thread2"); t1->Fork(SimpleThread, 1); t2->Fork(SimpleThread, 2); SimpleThread(3); } SimpleThread(int i) { printf(“Hello %d\n”, i); currentThread->Yield(); } Sample Example of Nacho Threads Start to fork and execute a function in each child thread. Parent also executes the same function Function executed by threads Create 2 new threads.

21 6.21 Nachos Lock Interface Lock can be in one of two states: locked or unlocked class Lock { public: Lock (char *name); //create a lock with unlocked state ~Lock(); void Acquire(); //Atomically waits until the lock is unlocked, and then sets the lock to be locked. void Release(); //Atomically changes the state to be unlocked. Only the thread who owns the lock can release. }

22 6.22 How to use locks Typically associate a lock with a piece of shared data for mutual execlusion. When a thread needs to access, it first acquires the lock, and then accesses data. Once access completes, it releases the lock. Example Lock *k= new Lock (“Lock”); k->Acquire(); Perform critical section operations. k->Release(); }

23 6.23 Thread synchronization: Example int a=0; void sum (int p){ a=a+1; printf(“T%d : a= %d\n”, p,a); } void main() { Thread *t=new Thread (“Child”); t->Fork(sum,1); sum(0); } The desired value for a is 2 at the end. Possible output: T0: a=1 T1: a=2 T0:a=2 T1: a=1 T0: a=1 T1:a=1

24 6.24 Synchronization with Locks: Example int a=0; Lock *k; void sum (int p){ int c; k->Acquire(); a=a+1; c=a; k->Release() printf(“%d : a= %d\n”, p,c); } void main() { Thread *t=new Thread (“Child”); k=new Lock(“Lock”); t->Fork(sum,1); sum(0); }

25 6.25 Semaphores in Nachos class Semaphore{ public: Semaphore (char *name, int counter); // initial counter value ~Semaphore(); void P(); //Atomically waits until the counter is greater than 0 and then decreases the counter void V(); //Atomically increases the counter }

26 6.26 Synchronization with Semaphore: Example int a=0; Semaphore *s; void sum (int p){ int c; s->P(); a=a+1; c=a; s->V(); printf(“%d : a= %d\n”, p,c); } void main() { Thread *t=new Thread (“Child”); s=new Semaphore(“S”,1); t->Fork(sum,1); sum(0); }

27 6.27 Semaphore for consumer-producer problem with unbounded buffer Semaphore can do more than mutual exclusion, and can synchronize a consumer/producer pipe Semaphore *data =new Semaphore(“Data”, 0);  Indicate # of data items available for consuming Consumer thread: while(1) { data-> P(); //wait until an item is available consume next item; } Producer thread: while(1){ produce next item; data->V(); //notify an item is available }

28 6.28 consumer-producer problem with bounded buffer Two semaphores: Semaphore *data =new Semaphore(“Data”, 0);  Indicate # of data items available for consuming Semaphore *space =new Semaphore(“Space”, 10); Indicate # of 10 data slots available. Producer thread: while(1){ produce next item; data->V(); //notify item is available }

29 6.29 consumer-producer problem with bounded buffer Two semaphores: Semaphore *data =new Semaphore(“Data”, 0);  Indicate # of data items available for consuming Semaphore *space =new Semaphore(“Space”, 10); Indicate # of 10 data slots available. Producer thread: while(1){ space->P();//wait until space is available produce next item; data->V(); //notify data is available }

30 6.30 consumer-producer problem with bounded buffer Semaphore *data =new Semaphore(“Data”, 0); Semaphore *space =new Semaphore(“Space”, 10); Producer thread: while(1){ space->P();//wait until space is available produce next item; data->V(); //notify data is available } Consumer thread: while(1){ data->P();//wait until data is available consume next item; }

31 6.31 consumer-producer problem with bounded buffer Semaphore *data =new Semaphore(“Data”, 0); Semaphore *space =new Semaphore(“Space”, 10); Producer thread: while(1){ space->P();//wait until space is available produce next item; data->V(); //notify data is available } Consumer thread: while(1){ data->P();//wait until data is available consume next item; space->V();//notify space is available }

32 6.32 Solution to Critical-section Problem 1. Locks 2. Semaphore 3. Conditional Variables

33 6.33 Condition Variables Improvement on busy waiting for acquiring a lock (spin locks) A thread is looping forever in checking if a lock is available or not.  The process “spins”  Waste CPU resource. Condition variables allow the waiting thread to be blocked, placed in a waiting queue, yielding CPU resource to somebody else. Similar problem in semaphore implementation wait (S) { //also called P() while (S <= 0) ; // no-op S--; }

34 6.34 Nachos Condition Variables Similar to Pthreads Condition Variables class Condition { public: Condition(char *name); ~Condition(); void Wait(Lock *ConditionLock); //Atomically releases the lock and waits. When it is returned, the lock is reacquired again. void Signal(Lock *ConditionLock); //Wake up one waiting thread to run. The lock is not released. void Broadcast(Lock *ConditionLock); //Wake up all threads waiting on the condition. The lock is not released. }

35 6.35 How to Use Condition Variables Associate a lock (L) and condition variable (cv) with data items to be accessed. An abstraction with lock/condition is known as monitor (Chapter 6.7). Typical program flow: Thread 1 L.Acquire(); When condition is not satisfied, cv.Wait(L); Critical Section; L.Release(); Thread 2: L.Acquire(); When condition can satisfy, cv.Signal(L). L.Relase();

36 6.36 Condition Variables for consumer- producer problem with unbounded buffer int avail=0; // # of data items available for consumption Lock *L; Condition *cv= new Condition (“condition”); Consumer thread: L.Acquire(); while (avail <=0) cv.Wait(L); consume next item; avail = avail-1; L.Release(); Producer thread: L.Acquire(); Produce next item; availl = avail+1; cv.Signal(L); //notify an item is available L.Release();

37 6.37 When to use condition broadcast() When waking up one thread to run is not sufficient. Example: concurrent malloc()/free() for allocation and deallocation of objects with non-uniform sizes. Lock *L; Condition *cv= new Condition (“condition”); char *malloc(int s) { L.Acquire(); while( cannot allocate a chunk of size s) cv.Wait(L); allocate free space of size s; L.Release(); return the chunk allocated. }

38 6.38 Use Broadcast() when space is freed void free (char *m){ L.Acquire(); deallocate m; cv.Broadcast(L); //wake up all threads waiting for space L.Release(); }

39 6.39 Running trace of malloc()/free() Initially 10 bytes are free. m() stands for malloc(). f() for free() Thread 1: m(10) – succ f(10) –broadcast m(7) – wait Resume m(7)-wait Thread 2: m(5) – wait Resume m(5)-succ f(5) –broadcast Thread 3: m(5) – wait Resume m(5)-succ m(3) –wait Resume m(3)-succ

40 6.40 Implementation of Synchronization Primitives Software solutions through shared memory data checking or message passing. Hardware-assisted solutions Properties (e.g. for implementing a lock) Mutual exclusion: only one gets a lock. Progress: when multiple threads try to acquire a lock, one can get it if nobody has it. Bounded waiting: lock waiting time is limited.

41 6.41 Software Solution for 2 processes/threads The two processes share one variable: int turn; // whose turn for the critical section Process 0 Process 1: Mutual exclusion? Progress? Bounded waiting? while (turn != 0); critical section turn= 1; //give turn to P1 while (turn != 1); critical section turn= 0; //give turn to P0

42 6.42 Mutual exclusion? Prove by contraction. Assume both Processes 0 and 1 are in the critical section. Process 0 Process 1: (turn==0) and (turn==1) is false while (turn != 1); critical section turn= 0; //give turn to P0 while (turn != 0); critical section turn= 1; //give turn to P1 turn==0 turn==1

43 6.43 Peterson’s Solution Two process software solution (Text book chapter 6.3) Assume that the LOAD and STORE instructions are atomic; that is, cannot be interrupted. The two processes share two variables: int turn;  indicates whose turn it is to enter the critical section. Boolean ready[2]  indicate if a process is ready to enter the critical section. ready[0] = true implies that process P 0 is ready!

44 6.44 Process P0: ready[0] = TRUE; turn = 1; while (ready[1] && turn == 1); critical section ready[0] = FALSE; Peterson’s Algorithm Enter critical section Exit critical section Process P1: ready[1] = TRUE; turn = 0; while (ready[0] && turn == 0); critical section ready[1] = FALSE; Mutual exclusion? Progress? Bounded waiting?

45 6.45 Process P0: ready[0] = TRUE; turn = 1; while (ready[1] && turn == 1); critical section ready[0] = FALSE; Mutual Execution? Prove by contradition Process P1: ready[1] = TRUE; turn = 0; while (ready[0] && turn == 0); critical section ready[1] = FALSE; Both conditions are true, which is not possible ready[0]=T and (Ready[1]=F or turn=0) ready[1]=T and (Ready[0]=F or turn=1)

46 6.46 Process P0: ready[0] = TRUE; turn = 1; while (ready[1] && turn == 1); critical section ready[0] = FALSE; Progress? Can both P0/P1 wait forever? Process P1: ready[1] = TRUE; turn = 0; while (ready[0] && turn == 0); critical section ready[1] = FALSE; Both conditions are true, which is not possible (Ready[1]=T and turn=1) (Ready[0]=T and turn=0)

47 6.47 Process P0: ready[0] = TRUE; turn = 1; while (ready[1] && turn == 1); critical section ready[0] = FALSE; Progress? Can P0 wait forever after P1 leaves Process P1: ready[1] = TRUE; turn = 0; while (ready[0] && turn == 0); critical section ready[1] = FALSE; Both conditions are true, which is not possible. (ready[1]=T and turn=1) ready[1]=F

48 6.48 Process P0: ready[0] = TRUE; turn = 1; while (ready[1] && turn == 1); critical section ready[0] = FALSE; Bounded waiting? Can P0 wait forever after P1 leaves Process P1: ready[1] = TRUE; turn = 0; while (ready[0] && turn == 0); critical section ready[1] = FALSE; Both conditions are true, which is not possible. P0 gets in after at most one entry by P1 (ready[1]=T and turn=1) ready[1]=F

49 6.49 Hardware Solution for Synchronization Many systems provide hardware support for critical section code Uniprocessors – could disable interrupts Currently running code would execute without preemption  Project 1. Generally too inefficient on multiprocessor systems  Operating systems using this not broadly scalable Modern machines provide special atomic hardware instructions  Atomic = non-interruptable Either test memory word and set value Or swap contents of two memory words

50 6.50 TestAndSet Instruction Definition: Get the value of a shared variable and then set it to TRUE atomically. boolean TestAndSet (boolean *target) { boolean rv = *target; *target = TRUE; return rv: }

51 6.51 Lock Solution using TestAndSet Shared boolean variable lock., True means somebody has acquired the lock. initialized to FALSE. Solution: Loop{ while ( TestAndSet (&lock )) ; // wait critical section; lock = FALSE; } Mutual exclusion? Progress? Bounded waiting? no

52 6.52 Process P0: Loop{ while(TestAndSet (&lock)); critical section lock = FALSE; } Mutual exclusion? Assume P0 gets first, and then P1 Process P1: Loop{ while(TestAndSet (&lock)); critical section lock = FALSE; } Conditions C1 and then C2: cannot be true C1: lock was F in last TestAndSet(). Now lock is T. C2: lock was F in last TestAndSet(). Now lock is T. Property: Lock=T  somebody is in the critical section Lock=F  nobody is in the critical section.

53 6.53 Process P0: Loop{ while(TestAndSet (&lock)); critical section lock = FALSE; } Progress? Assume P0/P1 wait forever while nobody is in the critical section Process P1: Loop{ while(TestAndSet (&lock)); critical section lock = FALSE; } Property: Lock=T  somebody is in the critical section Lock=F  nobody is in the critical section. C1: lock was F in last TestAndSet(). Now lock is T. P0 will get in first. Assume P1’s TestAndSet() is executed after C1.

54 6.54 Process P0: TestAndSet (&lock)); //get in … Lock=FALSE; //get out TestAndSet(&lock);// get in … Lock=FALSE; //get out TestAndSet(&lock);// get in … Lock=FALSE; //get out TestAndSet(&lock);// get in Bounded Waiting? Process P1: TestAndSet(&lock);// wait

55 6.55 Swap Instruction Definition: exchange values of two variables automatically. void Swap (boolean *a, boolean *b) { boolean temp = *a; *a = *b; *b = temp: }

56 6.56 Lock Solution using Swap Shared Boolean variable lock initialized to FALSE; Each process has a local Boolean variable key Solution: key = TRUE; while ( key == TRUE) Swap (&lock, &key ); critical section lock = FALSE; Mutual exclusion, progress. bounded waiting?

57 6.57 TestAndSet Solution with Bounded Waiting Lock =True or Waiting[i]==False Waiting[] F TT Assign with cyclic order for fairness T Critical Section:

58 6.58 waiting[i] = TRUE; key = TRUE; while (waiting[i] && key) key = TestAndSet(&lock); waiting[i] = FALSE; Critical section j = (i + 1) % n; while ((j != i) && !waiting[j]) j = (j + 1) % n; if (j == i) lock = FALSE; else waiting[j] = FALSE; Bounded-waiting Mutual Exclusion with TestAndSet() Loop if this process should wait and Lock =True Find a waiting process j and set waiting[j]=False Or Set Lock=False

59 6.59 Semaphore Implementation Atomic operations: wait (S) { //also called P() while ( S <= 0) ; // wait S--; } signal (S) { //also called V() S++; } Thus, 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 Note that applications may spend lots of time in critical sections and therefore this is not a good solution.

60 6.60 Semaphore Implementation with no busy waiting Each semaphore has a waiting queue. Two operations: block – place the process invoking the operation on the appropriate waiting queue.  Nachos: Thread:Sleep() wakeup – remove one of processes in the waiting queue and place it in the ready queue.

61 6.61 Semaphore Implementation with no Busy waiting (Cont.) Implementation of wait: wait(semaphore *S) { S->value--; if (S->value < 0) { add this process to S->list; block(); } Implementation of signal: signal(semaphore *S) { S->value++; if (S->value <= 0) { remove a process P from S->list; wakeup(P); }

62 6.62 Deadlock and Starvation Deadlock – two or more processes are waiting indefinitely for an event that can be caused by only one of the waiting processes Let S and Q be two locks: P 0 P 1 Acquire(S); Acquire(Q); Acquire (Q); Acquire (S);. Release (Q); Release(S); Release (S); Release(Q); Starvation – indefinite blocking. A process may never be removed from the semaphore queue in which it is suspended

63 6.63 Deadlock Avoidance Order the locks and always acquire the locks in that order. Eliminate circular waiting P 0 P 1 Acquire(S); Acquire(S); Acquire(Q); Acquire (Q);. Release(Q); Release (Q); Release(S); Release (S);

64 6.64 Classical Problems of Synchronization Bounded-Buffer Problem Barriers Readers and Writers Problem

65 6.65 65 Proj 1 Sample Code SimpleThread(){ numbOfThreadsStillRunning ++;//0 initially; … //for-loop to update SharedVariable numOfThreadsStillRunning--; while(numOfThreadsStillRunning>0) currentThread->Yield(); …// print the final value of SharedVariable } What’s wrong with this? (Discuss in groups of 2-3)

66 6.66 Barriers

67 6.67 Barriers called multiple times barrier(3);

68 6.68 68 Implement a Barrier using Semaphores barrier(N) { mutex->P(); //initial value 1 count ++; //initial value is 0; mutex->V(); while (count != N); } What’s wrong with this? (Discuss in groups of 2-3)

69 6.69 69 Implement a Barrier using Semaphores barrier(N) { mutex->P(); //Semaphore with initial value 1 if(++count != N) { //counter’s initial value is 0 mutex->V(); EveryoneHasReachedBarrier->P(); //Semaphore } else { count=0; mutex->V(); for(i = 1; i < N; ++i) EveryoneHasReachedBarrier->V(); } What’s wrong with this? (Discuss in groups of 2-3)

70 6.70 Readers-Writers Problem A data set is shared among a number of concurrent processes. Readers – only read the data set; they do not perform any updates Writers – can both read and write Problem: allow multiple readers to read at the same time. Only one writer can access the shared data at the same time. Reader/writer access permission table: ReaderWriter Reader OKNo WriterNONo

71 6.71 Readers-Writers (First try) writer do { wrt.Acquire(); // wrt is a lock // writing is performed wrt.Release(); } while (TRUE); Reader do { wrt.Acquire(); // Use wrt lock // reading is performed wrt.Release(); } while (TRUE); ReaderWriter Reader?? Writer??

72 6.72 Readers-Writers (second try) writer do { wrt.Acquire(); // Use wrt lock // writing is performed wrt.Release(); } while (TRUE); Reader do { readcount++; // add a reader counter. if(readcount==1) wrt.Acquire(); // reading is performed readcount--; if(readcount==0) wrt.Release(); } while (TRUE);

73 6.73 Readers-Writers (third try) writer do { wrt.P(); // Use wrt semaphore with initial value=1 // writing is performed wrt.V(); } while (TRUE); Reader do { readcount++; //initial value=0 if(readcount==1) wrt.P(); // reading is performed readcount--; if(readcount==0) wrt.V(); } while (TRUE);

74 6.74 Readers-Writers Problem (Text Book) Shared Data Data set Semaphore mutex initialized to 1 Semaphore wrt initialized to 1 Integer readcount initialized to 0

75 6.75 Readers-Writers Problem (textbook) The structure of a writer process do { wait (wrt) ; // writing is performed signal (wrt) ; } while (TRUE);

76 6.76 Readers-Writers Problem (Cont.) The structure of a reader process do { wait (mutex) ; readcount ++ ; if (readcount == 1) wait (wrt) ; signal (mutex) // reading is performed wait (mutex) ; readcount - - ; if (readcount == 0) signal (wrt) ; signal (mutex) ; } while (TRUE);


Download ppt "Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition Process/Thread Synchronization Modified from Chapter 6 for 170 with Nachos."

Similar presentations


Ads by Google