1 / 89

Synchronization

Synchronization. Ren-Song Ko National Chung Cheng University. Lecture objectives. To introduce the critical-section problem To present both software and hardware solutions of the critical-section problem. To introduce some c lassic s ynchronization p roblems. Lecture overview.

cbarham
Télécharger la présentation

Synchronization

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Synchronization Ren-Song Ko National Chung Cheng University

  2. Lecture objectives • To introduce the critical-section problem • To present both software and hardware solutions of the critical-section problem. • To introduce some classic synchronization problems

  3. Lecture overview • Introduction • The critical-section problem • Busy waiting solutions • Sleep and wakeup solutions • Semaphores • Monitors • Classicsynchronization problems

  4. 第一節

  5. Introduction • Processes may cooperate via information exchange to finish a task. • One approach is to use some common storage, in main memory or shared files, that each one can read and write.

  6. Printing example • To print a file, a process sends the file name in a special spooler directory. • Another process, the printer daemon, periodically checks to see if there are any files to be printed. • If yes, it prints them and then removes their names from the directory. • A producer-consumer, or bounded buffer, problem

  7. Printing example (animation) Spooler directory • Animation out : 5 out : 6 PrintDaemon in : 9 in : 8 ... PDFReader Printer 5 grade 6 a.txt Editer 7 b.txt 8 c.pdf ...

  8. Code (animation by code) while(true) { while (counter == BUFFER_SIZE) ; /* do nothing*/ buffer[in] = nextProducedItem; in = (in + 1) % BUFFER_SIZE; counter = counter + 1; } while(true) { while (counter == 0) ; /* do nothing*/ nextConsumedItem = buffer[out]; out = (out + 1) % BUFFER_SIZE; counter = counter - 1; } Term, variables must match with previous slide, counter++ changed to counter = counter+ 1

  9. Race condition • Note that the statement "counter = counter+1" may be implemented in machine language as • LDR R1 , [counter] (load) • ADD R1 , R1 , #1 (add) • STR R1 , [counter] (save) • where R1is a CPU register. Similarly, the statement "counter = counter -1" is implemented as follows: • LDR R2 , [counter] (load) • SUB R2 , R2 , #1 (sub) • STR R2 , [counter] (save)

  10. Race condition, cont. • Process is executed in the unit of machine instructions. • Correct execution should ensure each file is printed once.

  11. Race condition, cont. (animation by code) • Animation, correct and incorrect incorrect correct P : LDR R1 , [counter] ; R1 = 5 P : ADD R1 , R1, #1 ; R1 = 6 P : STR R1 , [counter] ; counter = 6 C : LDR R2 , [counter] ; R2 = 6 C : SUB R2 , R2, #1 ; R2 = 5 C : STR R2 , [counter] ; counter = 5 P : LDR R1 , [counter] ; R1 = 5 P : ADD R1 , R1, #1 ; R1 = 6 C : LDR R2 , [counter] ; R2 = 5 C : SUB R2 , R2, #1 ; R2 = 4 P : STR R1 , [counter] ; counter = 6 C : STR R2 , [counter] ; counter = 4

  12. Race condition, cont. • Situations like this, where several processes are accessing some shared data and the final result depends on running in a particular order, are called race conditions. • Debugging programs containing race conditions is difficult. • It is hard to identify sources of bugs. • Most of test results are correct • Same input but different output • Bugs cannot repeat

  13. To avoid race conditions • To guard against the race condition, we need to ensure that only one process at a time can be manipulating the shared variable counter. • That part of the program where the shared data is accessed is called the critical section. • If we could ensure that no two processes were ever in critical sections at the same time, we could avoid race conditions.

  14. 第二節

  15. The critical-section problem • The critical-section problem is to design a protocol that the processes can use to cooperate. • A complete solution to the critical-section problem must satisfy the following requirements: • Mutual exclusion • No two processes may be simultaneously inside their critical sections. • Progress • No process running outside its critical section may block other processes. • Bounded waiting • No process should have to wait forever to enter its critical section. • Moreover, no assumptions may be made about speeds or the number of CPUs.

  16. 第三節

  17. Busy waiting solutions • Disabling interrupts • Software solutions • Problematic attempts • Lock variables • Strict alternation • Peterson's solution • Bakery algorithm • Hardware instructions

  18. Disabling interrupts • Have each process disable all interrupts just after entering its critical section and re-enable them just before leaving it. • With interrupts disabled, CPU will not be switched to another process and the process can manipulate shared data without intervention of other process. • It is unwise for user processes to turn off interrupts. • What if never turned them on again? • Besides, does not work multiprocessor systems • Only affects the CPU that executed the disable instruction. • The other ones can still access the shared data. • However, it is convenient for the kernel to disable interrupts for a few instructions to update system data structures. • The conclusion is: disabling interrupts is often a useful technique within OS itself but is not an appropriate for user processes.

  19. Lock variables (animation by code) • One shared variable • bool lock = FALSE; • When a process wants to enter its critical section, it first tests lock. • If lock is FALSE. the process sets it to TRUE and enters. • If TRUE, the process just waits until it becomes FALSE. while(TRUE) { while(lock); // busy waiting // 1 lock = TRUE; // 2 CRITICAL SECTION //3 lock = FALSE; // 4 REMAINDER SECTION // 5 }

  20. Lock variables, cont. • Unfortunately, this idea violates the mutual exclusion requirement. • Animation • Suppose that one process reads the lock and sees that it is 0. • Before it can set the lock to 1, another process is scheduled, runs, and sets the lock to 1. • When the first process runs again, it will also set the lock to 1, and two processes will be in their critical sections at the same time. lock : FALSE P0 P1 while(TRUE) { while(lock); // 1 lock = TRUE; // 3 CRITICAL SECTION //5 lock = FALSE; REMAINDER SECTION } while(TRUE) { while(lock); // 2 lock = TRUE; // 4 CRITICAL SECTION //6 lock = FALSE; REMAINDER SECTION }

  21. Strict alternation (animation by code) • Processes P0 and P1 take turns using the shared variable turn. • int turn = 0; turn : 0

  22. Strict alternation, cont. • Unfortunately, this idea violates the progress requirement. • Animation • When P0 leaves the critical section, it sets turn to 1, to allow P1 to enter its critical section. • Suppose that P1 finishes its critical section quickly, so both processes are in their noncritical sections, with turn set to 0. • Now P0 executes its noncritical section slowly with turn set to 0. At this point, P1 finishes its noncritical section and goes back to the top of its loop. • Unfortunately, it is not permitted to enter its critical section now, because turn is 0 and P0 is busy with its noncritical section. • This situation violates progress requirement: P1 is being blocked by a process not in its critical region. Going back to the spooler directory discussed above, if we now associate the critical section with reading and writing the spooler directory, P1 would not be allowed to print another file because P0 was doing something else. • Put differently, taking turns is not a good idea when one of the processes is much slower than the other. • In fact, this solution requires that the two processes strictly alternate in entering their critical sections.

  23. Strict alternation turn : 0

  24. Peterson's solution • Two processes solution • Assume that the LOAD and STORE instructions are atomic; that is, cannot be interrupted. • The two processes share two variables: • int turn; • bool flag[2] • The variable turn indicates whose turn it is to enter the critical section. • The flag array is used to indicate if a process is ready to enter the critical section. flag[i] = TRUE implies that process Pi is ready!

  25. Algorithm for Pi (animation by code) while(TRUE){ flag[i] = TRUE; // declare intention //1 other = 1-i; // other process //2 turn = other; // be courteous //3 while(flag[other] && turn == other); // busy waiting //4 CRITICAL SECTION //5 flag[i] = FALSE; // indicate departure //6 REMAINDER SECTION //7 }

  26. Correctness of the algorithm • Need to show that: • Mutual exclusion is preserved. • The progress requirement is satisfied. • The bounded waiting requirement is met.

  27. Satisfaction of mutual exclusion requirement • Each Pi enters its critical section only if either flag[other] == FALSE (other has no intention) or turn == i (i’s turn). • Also, if both can be executing in their critical sections at the same time, then flag[0] == flag[1] == TRUE (both have intention). • These two observations implies that P0 and P1 cannot pass their while statements at the same time since turn cannot be 0 and 1 at the same time. • Hence, one of the processes - say P0 - must have pass the while statement, whereas P1 had to wait for flag[0] == FALSE or turn == 1. • At that time, flag[0] == TRUE, and turn == 0, and this condition will persist as long as P0 is in its critical section. • Hence, mutual exclusion is preserved.

  28. Satisfaction of progress and bounded waiting requirements • P0 can be prevented from entering the critical section only if it is stuck in the while loop with the condition flag[1] == TRUE and turn == 1. • If P1 is not ready to enter the critical section, then flag[1] == FALSE, and P0 can enter its critical section. • If P1 has set flag[1] to TRUE and is also executing in its while statement, then either turn == 0 or turn == 1. • If turn == 0, then P0 will enter the critical section. • If turn == 1, then P1 will enter the critical section. However, once P1 exits its critical section, it will reset flag[1] to FASLE, allowing P0 to enter its critical section. • If P1 resets flag[1] to TRUE, it must also set turn to 0. • Thus, since P0 does not change the value of turn while executing the while statement, P0 will enter the critical section (progress) after at most one entry by P1 (bounded waiting).

  29. Lock (correct approach) • The first attempt fails because a process may be preempted while it is accessing the lock. • Thus, no preemption during lock accessing will work, i.e., lock accessing is a critical section. while (TRUE){ ACQUIRE LOCK// critical section CRITICAL SECTION RELEASE LOCK// critical section REMAINDER SECTION }

  30. Bakery algorithm • Multi-processes solution • When entering the critical section • Take a number and wait • Can’t guarantee that numbers are distinct • Process with lowest process-id goes first

  31. Bakery algorithm, cont. (animation by code) bool choosing[n]; // initially FALSE // 1 int number[n]; // initially 0 //2 /* process i */ choosing[i] = TRUE; number[i] = max(number[0], ..., number[n]) + 1; choosing[i] = FALSE; for(j = 0; j != i; j++) { while(choosing[j]); while(number[j] && number[j] <= number[i]); } for(j = i + 1; j < n; j++) { while(choosing[j]); while(number[j] && number[j] < number[i]); } CRITICAL SECTION //5 number[i] = 0; // 6 REMAINDER SECTION // 7 // 3 pick a number // 4 busy wait

  32. Hardware instructions • Software solutions are complex and awkward. • A little help from hardware • special atomic hardware instructions • atomic = non-interruptible • TestAndSet: test a boolean variable and set value TRUE • Swap: swap contents of two boolean variables

  33. TestAndSet instruction (animation by code) • Definition: bool TestAndSet(bool *item) { bool value = *item; // 1 *item = TRUE; // 2 return value; // 3 }

  34. Solution using TestAndSet (animation by code) • One shared variable • bool lock = FALSE; do { while(TestAndSet(&lock)); // busy waiting // 1 CRITICAL SECTION // 2 lock = FALSE; // 3 REMAINDER SECTION // 4 } while(TRUE);

  35. Swap instruction (animation by code) • Definition: bool Swap(bool *one, bool *two) { bool temp = *one; // 1 *one = *two; // 2 *two = temp; // 3 }

  36. Solution using Swap (animation by code) • One shared variable • bool lock = FALSE; • Each process has its own boolean variable key do { key = TRUE; // 1 /* try to use key to unlock the lock if successful, key will be FALSE */ while(key == TRUE) Swap(&lock, &key); // 2 CRITICAL SECTION //3 lock = FALSE; //4 REMAINDER SECTION //5 } while(TRUE);

  37. So far, busy waiting solutions • Solution 1: disabling interrupts • big hammer • Solution 2: with shared variables • Peterson’s solution • complex but no hardware support • works even on multiprocessors • 2b: TestAndSet • simpler but assumes TestAndSet (or equiv) instruction

  38. 第四節

  39. Sleep and wakeup solutions • So far the solutions are correct, but have the defect of requiring busy waiting. • If a process is not permitted to enter its critical section, it just sits in a tight loop waiting until permission granted. • Not only waste CPU time, but also have priority inversion problem

  40. Priority inversion problem (animation) • Priority scheduling • Two processes, H with high priority and L with low priority • At a certain moment, L is in its critical section and H becomes ready to run. • H begins busy waiting. • Since L is never scheduled while H is running, L never gets the chance to finish its critical section. • H waits forever.

  41. Sleep and wakeup solutions, cont. • When a process is not allowed to enter its critical section, instead of wasting CPU time, block or suspend the process until another process wakes it up. • Each critical section has an associated waiting queue. • Two operations: • sleep– place the process invoking the operation on the appropriate waiting queue associated with the critical section. • wakeup– remove one of processes in the waiting queue and place it in the ready queue.

  42. 第五節

  43. Semaphores • E. W. Dijkstra (1965) • A semaphore S is a non-negative integer variable • Can only be accessed via two atomic operations: • wait(S) decrements S by one if possible, otherwise it waits until S becomes positive, then decrements it; i.e. (idea only, not actual implementation), wait(S) { while S <= 0; // no-op S--; } • signal(S) increments S by one; i.e., signal(S) { S++; }

  44. Semaphore as synchronization tool • Counting semaphore– integer value can range over an unrestricted domain • Binary semaphore– integer value can range only between 0 and 1 • Also known as a mutex lock • Used by two or more processes to ensure that only one of them can enter its critical section. • If each process does a wait just before entering its critical section and a signal just after leaving it, mutual exclusion is guaranteed. Semaphore S; // shared variable, initialized to 1 wait(S); CRITICAL SECTION signal(S);

  45. Semaphore is a critical section problem • Must guarantee that no two processes can execute wait() and signal() on the same semaphore at the same time • Thus, the semaphore accessing is a critical section.

  46. Implementing semaphores • Various approaches described can be used to implement semaphores, i.e., a critical section problem. • For example, TestAndSet may be used to implement a binary semaphore as following • Because of TestAndSet definition, we let a process enter its critical section when S is 0, and wait when S is 1; void wait(S) { while(TestAndSet(&S)); } void signal(S) { S = 0; }

  47. Are we done yet? • Not quite! • The shared variable solutions require busy waiting • bad: this can be inefficient - the locked out process needs to be running • worse: can deadlock if the waiting process has higher priority in the scheduler • We’d usually prefer a blocking solution

  48. Semaphore implementation with no busy waiting • With each semaphore there is an associated waiting queue. • Instead of an integer, a semaphore is a two items data structure: typedef struct { int value; struct queue *list; // waiting queue } semaphore; • Use sleep and wakeup to operate the waiting queue.

  49. Implementation of wait() with no busy waiting (animation by code) wait(semaphore *S){ if (S->value <= 0) { //1 add this process to S->list //2 sleep(); //3 } S->value--; // 4 }

  50. Implementation of signal() with no busy waiting (animation by code) signal(semaphore *S){ S->value++; // 1 if (S->value <= 0) { // 2 remove a process from S->list // 3 wakeup(P); // 4 } }

More Related