OSTEP: Chapter 26
Review idea of atomic operations. Example: counting contest.
Shared variable:
volatile int i; |
|
Process A
i = 0; while (i < 10) { i++; } cout << "A wins"; |
Process B
i = 0; while (i > -10) { i--; } cout << "B wins"; |
Synchronization: the use of atomic operations to ensure the correct operation of cooperating processes.
Person A | Person B | |
3:00 3:05 3:10 3:15 3:20 3:25 3:30 |
Look in fridge. Out of milk. Leave for store. Arrive at store. Leave store. Arrive home, put milk away. |
Look in fridge. Out of milk. Leave for store. Arrive at store. Leave store. Arrive home. OH NO! |
What does correct mean? One of the most important things in synchronization is to figure out what you want to achieve.
Mutual exclusion: Mechanisms that ensure that only one person or process is doing certain things at one time (others are excluded). E.g. only one person goes shopping at a time.
Critical section: A section of code, or collection of operations, in which only one process may be executing at a given time. E.g. shopping. It is a large operation that we want to make "sort of" atomic.
There are many ways to achieve mutual exclusion, which we will be discussing all of this week. Most involve some sort of locking mechanism: prevent someone from doing something. For example, before shopping, leave a note on the refrigerator.
Three elements of locking:
1. | Must lock before using. | leave note |
2. | Must unlock when done. | remove note |
3. | Must wait if locked. | do not shop if note |
Processes A & B | |
1 2 3 4 5 6 7 |
if (NoMilk) { if (NoNote) { Leave Note; Buy Milk; Remove Note; } } |
What happens if we leave the note at the very beginning: does this make everything work?
Process A | Process B | |
1 2 3 4 5 6 |
if (NoNote) { if (NoMilk) { Buy Milk; } Leave Note; } |
if (Note) { if (NoMilk) { Buy Milk; } Remove Note; } |
Suppose B goes on vacation. A will buy milk once and will not buy any more until B returns. Thus this really does not really do what we want; it is unfair, and leads to starvation.
Process A | |
1 2 3 4 5 6 7 |
Leave NoteA; if (NoNoteB) { if (NoMilk) { Buy Milk; } } Remove NoteA; |
What can we say about this solution?
Solution is almost correct. We just need a way to decide who will buy milk when both leave notes (somebody has to hang around to make sure that the job gets done).
Process B stays the same as before.
Process A | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Leave NoteA; if (NoNoteB) { if (NoMilk) { Buy Milk; } } else { while (NoteB) { DoNothing; } if (NoMilk) { Buy Milk; } } Remove NoteA; |
How do we know this is correct?
This solution works. But it still has two disadvantages: