Synchronization Fall 2016 Reading
• Chapter 2, Sec 2.3, “Modern Operating Systems, Fourth Ed.”, Andrew S. Tanenbaum • you may skip 2.3.9 and 2.3.10
• “POSIX Threads Programming”, available at: https:// computing.llnl.gov/tutorials/pthreads/
• Andrew D. Birrell, “An Introduction to Programming with Threads”, available at: https://birrell.org/andrew/papers/035- Threads.pdf
Fall 2016 Operating Systems 2 Parallelism vs Concurrency
• A parallel system can perform more than one task simultaneously • multicore, multiprocessor, GPU • A concurrent system supports more than one task by allowing all the tasks to make progress • one processor
Fall 2016 Operating Systems 3 Can All Code be Parallelized? int params[10] int params[10] for(i=0;i<10;i++) for(i=0;i<10;i++)
{ {
dosomething(params[i]); val = docomplicated(params[i],val);
} }
can be parallelized cannot be parallelized
Fall 2016 Operating Systems 4 Outline
• Interprocess Communication
• Race Conditions
• Critical Regions
• Case Study
• Hardware Solution
• Semaphores
• Mutexes and Condition Variables
• More Mutual Exclusion Mechanisms
Fall 2016 Operating Systems 5 Independent Threads
• A thread that cannot affect or be affected by any other threads
• Its state is not shared
• The input state determines its result —> deterministic
• Reproducible
• Stop and continue without “side effects”
Fall 2016 Operating Systems 6 Communication Between Processes
• Sharing Storage
• Main Memory
• Files
• Messages
Fall 2016 Operating Systems 7 Cooperating Threads
• These threads share state
• Their behaviour is nondeterministic as it depends on relative execution of threads
• Their behaviour might be irreproducible
Fall 2016 Operating Systems 8 Cooperating Threads: Example 1
• x and y are shared variables between processes A and B
• Their initial values are zeros
Process A Process B
x=1 y=2
x=y+1 y=y*2
which order is correct?
Fall 2016 Operating Systems 9 Cooperating Threads: Example 2
• i is a shared variable between processes A and B
Process A Process B
i=0; i=0; while(i<10) while(i>-10) { { i++; i--; } } printf(“A wins”); printf(“B wins”);
which order is correct?
Fall 2016 Operating Systems 10 Case Study: Print Spooling
Processes A and B want to access shared memory at the same time
the next file to be printed processes A and B are queuing files for printing the next free slot in the directory
which order is correct?
Fall 2016 Operating Systems 11 Case Study:Too Much Milk Problem
Person A Person B
3:00 Look in Fridge: no milk
3:05 Leave for store
3:10 Arrive at store Look in Fridge: no milk
3:15 Leave at store Leave for store
3:20 Arrive at Home, put milk away Arrive at store
3:25 Leave at store
3:30 Arrive at Home, too much milk!
which order is correct?
Fall 2016 Operating Systems 12 Atomic Operations
• Atomic operation: can be performed entirely with no interruption
• an operation that can be done entirely before the interrupts are checked
• Mostly, memory load and store operations are atomic
• Many of the other operations are not atomic:i++, i--,x=y+3
• Atomic operations are needed to make higher level constructs to simulate atomicity
Fall 2016 Operating Systems 13 Outline
• Interprocess Communication
• Race Conditions
• Critical Regions
• Mutual Exclusion
• Case Study
• Hardware Solution
• Semaphores
• Mutexes and Condition Variables
• More Mutual Exclusion Mechanisms
Fall 2016 Operating Systems 14 Race Condition
• Race condition: Two or more threads (processes) are reading and writing shared data and the final result depends on the relative order of executing these threads (processes)
• Debugging is hard!
• Some final answers are not correct
Fall 2016 Operating Systems 15 Synchronization
• Order of interleaving between threads:
• Irrelevant: operations are independent
• Relevant: operations are dependent
• Any possible interleaving should result in a correct answer
• Synchronization: using atomic operations to ensure correct operations of cooperating threads
• Correct interleaving between threads
• Controls order of execution of threads
Fall 2016 Operating Systems 16 Outline
• Interprocess Communication
• Race Conditions
• Critical Regions
• Mutual Exclusion
• Case Study
• Hardware Solution
• Semaphores
• Mutexes and Condition Variables
• More Mutual Exclusion Mechanisms
Fall 2016 Operating Systems 17 Critical Region (Critical Section)
• Critical Region: a section of code (several operations) in which only one thread may be executing at a given time
• shared memory is (or other shared resources are) accessed in this section of the code
• the objective is that this section be executed atomically with no interruptions —> no two threads are executing in this section at the same time
• Mutual exclusion: a mechanism used to ensure that only one thread is executing in a critical section
• typically done through locking mechanism, for example, leave a note on the refrigerator before shopping for milk
Fall 2016 Operating Systems 18 Example: Critical Region
Solution 1 Solution 2 Solution 3
1 Enter_Critical_Section if (milk == 0) { Enter_Critical_Section
2 if (milk == 0) { Enter_Critical_Section if (milk == 0) {
3 buyMilk() buyMilk() Exit_Critical_Section
4 } Exit_Critical_Section ……………
5 Exit_Critical_Section } Enter_Critical_Section
6 buyMilk()
Exit_Critical_Section
}
Fall 2016 Operating Systems 19 Example: Critical Region
Solution 1 Solution 2 Solution 3
1 Enter_Critical_Section if (milk == 0) { Enter_Critical_Section
2 if (milk == 0) { Enter_Critical_Section if (milk == 0) {
3 buyMilk() buyMilk() Exit_Critical_Section
4 } Exit_Critical_Section ……………
5 Exit_Critical_Section } Enter_Critical_Section
6 buyMilk()
Exit_Critical_Section
}
Fall 2016 Operating Systems 20 Conditions for a Good Mutual Exclusion Solution
• No two processes may be simultaneously inside their critical regions
• No assumptions may be made about speeds or the number of CPUs
• No process running outside its critical region may block any process
• No process should have to wait forever to enter its critical region
Fall 2016 Operating Systems 21 Summary
• Atomic operation: can be performed entirely with no interruption
• Race condition: Final result depend on the relative order of executing threads
• Critical Section: a section of code in which only one thread may be executing at a given time
• Mutual exclusion: a mechanism used to create critical section
• Synchronization: using atomic operations to ensure correct operations of cooperating threads
Fall 2016 Operating Systems 22 Outline
• Interprocess Communication
• Race Conditions
• Critical Regions
• Mutual Exclusion
• Case Study
• Hardware Solution
• Semaphores
• Mutexes and Condition Variables
• More Mutual Exclusion Mechanisms
Fall 2016 Operating Systems 23 Mutual Exclusion Mechanisms
• Hardware:
• Disable interrupts
• Special instructions busy waiting • Software:
• Peterson’s solution
• Semaphores
• Mutex
• Monitors
• Message passing
Fall 2016 Operating Systems 24 Revisiting the Too Much Milk Problem
Person A Person B
3:00 Look in Fridge: no milk
3:05 Leave for store
3:10 Arrive at store Look in Fridge: no milk
3:15 Leave at store Leave for store
3:20 Arrive at Home, put milk away Arrive at store
3:25 Leave at store
3:30 Arrive at Home, too much milk!
Fall 2016 Operating Systems 25 Too Much Milk Problem — Attempt 1
Person A & B
1 if (milk == 0) {
2 if (note == 0) {
3 note = 1
4 buyMilk()
5 note = 0
6 }
7 }
Fall 2016 Operating Systems 26 Lock Variables
• Use a shared (lock) variable, initially 0
• When a process wants to enter its critical region
• it tests the lock
• if the lock is 0, set the lock to 1 and enters the critical region
• if the lock is 1, wait until it becomes 0
• Therefore, 0 means that no process is in its critical region, and 1 means that a process is in its critical region
• Does this work?
Fall 2016 Operating Systems 27 Too Much Milk Problem — Attempt 2
Person A Person B
1 while (note == 0) { while (note == 1) {
2 if (milk == 0) { if (milk == 0) {
3 buyMilk() buyMilk()
4 } }
5 note = 1 note = 0
6 } }
Note meaning: A buys if no note, B buys if there is a note.
Fall 2016 Operating Systems 28 Strict Alternation
• Use an integer variable turn, initially 0, keeps track of whose turn it is to enter the critical region
• Procesdure:
• process 0 inspects turn, finds it to be 0, and enters its critical region
• process 1 finds turn to be 0, it continues to wait until it changes to 1
• A process changes the value of turn before leaving the critical section
• Advantage: avoids races
• Disadvantage: violates condition 3
• Note: spin lock is a lock that uses busy waiting
Fall 2016 Operating Systems 29 Too Much Milk Problem — Attempt 3
Person A Person B
1 noteA = 1 noteB = 1
2 if (noteB == 0) { if (noteA == 0) {
3 if (milk == 0) { if (milk == 0) {
4 buyMilk() buyMilk()
5 } }
6 } }
7 noteA = 0 noteB = 0
Use separate notes for A and B
Fall 2016 Operating Systems 30 Too Much Milk Problem — Attempt 4
Person A Person B
1 noteA = 1 noteB = 1
2 if (noteB == 0) { while (noteA == 1) {
3 if (milk == 0) { //do nothing
4 buyMilk() }
5 } if (milk == 0) {
6 } buyMilk()
7 noteA = 0 }
noteB = 0
Fall 2016 Operating Systems 31 Too Much Milk Problem — Attempt 4 — Comments
• Works — hurray !
• Disadvantages:
• Asymmetric solution
• Involves busy-waiting (Continuously testing a variable until some value appears)
Fall 2016 Operating Systems 32 Peterson’s Algorithm
Credit: Andrew Tanenbaum, Modern Operating Systems: 4th ED
Fall 2016 Operating Systems 33 Outline
• Interprocess Communication
• Race Conditions
• Critical Regions
• Mutual Exclusion
• Hardware Solution
• Case Study
• Semaphores
• Mutexes and Condition Variables
• More Mutual Exclusion Mechanisms
Fall 2016 Operating Systems 34 Hardware: Disabling Interrupts
• Mechanism of each process:
• disable interrupts when entering the critical region
• enable interrupts just before leaving the critical region
• Disadvantages:
• It is unwise to allow user processes to switch off interrupts
• Not suitable for multiprocessors
• Usage: the kernel can use it while updating processes information
Fall 2016 Operating Systems 35 Hardware: Disabling Interrupts — Example
Solution - Disabling Interrupts
1 Disable-Interrupts
2 if (milk == 0) {
3 buyMilk()
4 }
5 Enable-Interrupts
6
Fall 2016 Operating Systems 36 Hardware Instructions
• Atomic instruction, no interruption while the processor is executing it
• the memory bus is locked (different from disabling interrupts!)
• Test and Set Lock (TSL)
• read a memory address into a register
• set the value in the memory address to nonzero (one)
• XCHG
• exchange the location of two locations atomically (e.g. memory and register)
Fall 2016 Operating Systems 37 Test and Set Lock (TSL)
• Entering and leaving critical section using the TSL instruction
Fall 2016 Operating Systems 38 XCHG
• Entering and leaving critical section using the XCHG instruction
Fall 2016 Operating Systems 39 Hardware Instructions — Advantages
• Suitable for any number of processes
• Simple and easy to verify
• Can support multiple critical sections, where each critical section will have to have its variable
Fall 2016 Operating Systems 40 Hardware Instructions — Disadvantages
• Busy waiting (Why it is bad? When is it OK?)
• Starvation is possible
• definition: some processes are not able to enter the critical section
• example: P1 and P2 keep entering the critical section, while P3 is unable to enter it
• Deadlock is possible progress ? progress
• definition: two or more processes are unable to proceed
• Example: P1 is executing in the critical section, P2 is chosen to execute because it has higher priority, P2 is busy waiting
Fall 2016 Operating Systems 41 Outline
• Interprocess Communication
• Race Conditions
• Critical Regions
• Mutual Exclusion
• Hardware Solution
• Case Study: Producer Consumer
• Semaphores
• Mutexes and Condition Variables
• More Mutual Exclusion Mechanisms
Fall 2016 Operating Systems 42 Case Stude: Producer-Consumer Problem (AKA Bounded Buffer Problem)
• Two processes share a fixed size buffer
• The producer process adds items to the buffer
• The consumer process removes items from the buffer
• Rules:
• The producer and consumer cannot access the buffer at the same time
• If the buffer is full, a producer cannot add new items to the buffer
• If the buffer is empty, a consumer cannot remove an item from the buffer
Fall 2016 Operating Systems 43 Credit: William Stallings, Operating Systems: Internals and Design Principles, 7th ED
Fall 2016 Operating Systems 44 The producer-consumer problem with a fatal race condition
Fall 2016 Operating Systems 45 Race Condition in the Solution?
• Case 1:
• buffer is empty, consumer read count and it is 0
• switch to producer
• producer insert item in the buffer, increment count to 1
• wakeup the consumer (lost!)
• switch to consumer
• check the value read earlier, sleep (forever!)
• Case 2:
• updating count simultaneously
Fall 2016 Operating Systems 46 Outline
• Interprocess Communication
• Race Conditions
• Critical Regions
• Mutual Exclusion
• Hardware Solution
• Case Study: Producer Consumer
• Semaphores
• Mutexes and Condition Variables
• More Mutual Exclusion Mechanisms
Fall 2016 Operating Systems 47 Semaphores
• Idea:
• A process blocks instead of busy waiting
• Use a variable semaphore to count wakeup signals
• Semaphore:
• a synchronization variable
• a queue of waiting processes
• Semaphore operations (atomic):
• Signal (V, up): increment the semaphore variable and wake up any waiting processes
• Wait (P, down): decrement the semaphore variable and wait in a queue if it becomes negative
Fall 2016 Operating Systems 48 Semaphore Primitives
Note: semWait = down = P, semSignal = up = V
Credit: William Stallings, Operating Systems: Internals and Design Principles, 7th ED
Fall 2016 Operating Systems 49 Semaphores — Too Much Milk
Person A & B
1 semaphore OKToBuyMilk initialized to 1
2 down(&OKToBuyMilk)
3 if (milk == 0) {
4 buyMilk()
5 }
6 up(&OKToBuyMilk)
Binary Semaphores are initialized to 1 and used by two or more processes to ensure that only one of them can enter its critical region at the same time
Fall 2016 Operating Systems 50 Producer-Consumer Using Semaphores
Fall 2016 Operating Systems 51 Implementing Semaphores
• Semaphores has to be atomic
• Semaphore operations are implemented as system calls
• use disabling interrupt if 1 CPU
• use hardware instruction (e.g. TSL or XCHG) if multiple CPUs
• Questions:
• Is disabling interrupt OK?
• Is busy waiting OK?
Fall 2016 Operating Systems 52 Semaphore Usage
• Two usage:
• Mutual exclusion (e.g. mutex semaphore in the producer- consumer problem solution)
• Synchronization (e.g. full and empty semaphores in the producer-consumer problem solution)
Fall 2016 Operating Systems 53 Outline
• Interprocess Communication
• Race Conditions
• Critical Regions
• Mutual Exclusion
• Hardware Solution
• Case Study: Producer Consumer
• Semaphores
• Mutex and Condition Variables
• More Mutual Exclusion Mechanisms
Fall 2016 Operating Systems 54 Mutex
• A mutex (lock) is a shared variable that can be in one of two states: locked, unlocked
• Notes:
• Similar to semaphore except that they do not have counting feature
• A mechanism that provides mutual exclusion
• Implemented in thread libraries such as Pthread
• Can be implemented in user space (?) using the instructions TSL or XCHG
Fall 2016 Operating Systems 55 Mutex Operations
• mutex_lock (acquire):
• Mark the lock as owned by the current thread
• If the lock is not free (owned by another thread), then wait (!)
• mutex_unlock (release):
• Given that the current thread owns the lock, it can make it free
No kernel calls are needed!
Fall 2016 Operating Systems 56 Implementation of mutex_lock and mutex_unlock
Fall 2016 Operating Systems 57 Using Mutex Operations for Mutual Exclusion
• Usage:
• Call mutex-lock before accessing critical section.
• If mutex is unlocked, the operation succeeds and the thread access critical section
• If mutex is already locked, the thread blocks
• When the thread in critical section finishes, it calls mutex_unlock
Fall 2016 Operating Systems 58 Too Much Milk Problem
Solution - Mutex
1 mutex_lock
2 if (milk == 0) {
3 buyMilk()
4 }
5 mutex_unlock
6
Fall 2016 Operating Systems 59 Producer Consumer - Mutex - Initialization
#include
#define MAX_ELEM 10 //buffer int buffer[MAX_ELEM]; int count = 0, head = 0, tail = 0; //mutex pthread_mutex_t pc_mutex;
Fall 2016 Operating Systems 60 Producer Consumer - Mutex - Produce
void * produce(void* threadarg) { int i; for(i=0;i Fall 2016 Operating Systems 61 Producer Consumer - Mutex - Consume void * consume(void* threadarg) { int i; for(i=0;i Fall 2016 Operating Systems 62 Producer Consumer - Mutex - Main int main() { pthread_t producer, consumer; //initialize mutex pthread_mutex_init(&pc_mutex, NULL); //create producer thread pthread_create(&producer, NULL, produce, NULL); //create consumer thread pthread_create(&consumer, NULL, consume, NULL); //wait for threads to finish pthread_join(producer, NULL); pthread_join(consumer, NULL); //cleanup pthread_mutex_destroy(&pc_mutex); /*free up the mutex*/ //exit main thread pthread_exit(NULL); } Fall 2016 Operating Systems 63 Revisiting Producer Consumer Solution Using Mutex • Empty/full cases is not handled • Solutions: • Attempt 1: use busy waiting • Attempt 2: use condition variables Fall 2016 Operating Systems 64 Producer Consumer - Mutex - Produce - Attempt 1 void * produce(void* threadarg) { int i; for(i=0;i Fall 2016 Operating Systems 65 Producer Consumer - Mutex - Consume - Attempt 1 void * consume(void* threadarg) { int i; for(i=0;i Fall 2016 Operating Systems 66 Condition Variables • Objective: allow threads to block (wait) due to some condition not being met • Operations for creating and destroying conditions: • pthread_cond_init (condition,attr) • pthread_cond_destroy (condition) • pthread_condattr_init (attr) • pthread_condattr_destroy (attr) Fall 2016 Operating Systems 67 Condition Variables Usage • Operations for Waiting and Signalling threads: • pthread_cond_wait (condition,mutex): release mutex, put thread to sleep until condition is signalled • pthread_cond_signal (condition): if any threads are waiting on condition, wake up one of them. When thread wakes up, it needs to re-acquire the mutex • pthread_cond_broadcast (condition): same as signal, except that it wakes up all waiting threads on the condition • Usage example: lock a mutex, wait on a condition variable, possibly block (unlock mutex) and get signaled later Fall 2016 Operating Systems 68 Condition Variables Usage - Notes • Notes: • After signalling a thread, it will wait in a queue until the signalling thread releases the lock • After a thread wakes up, there is no guarantee that the condition is still valid. The condition is needed to be checked again! • Unlike semaphores, conditions have no memory. If a signal is sent to a condition and no threads are waiting, the signal is lost Fall 2016 Operating Systems 69 Producer Consumer - Mutex - Initialization - Attempt 2 #include #define MAX_ELEM 10 //buffer int buffer[MAX_ELEM]; int count = 0, head = 0, tail = 0; //mutex pthread_mutex_t pc_mutex; //condition variables pthread_cond_t cond_availData, cond_availSpace; Fall 2016 Operating Systems 70 Producer Consumer - Mutex - Produce Attempt 2 void * produce(void* threadarg) { int i; for(i=0;i Fall 2016 Operating Systems 71 Producer Consumer - Mutex - Consume - Attempt 2 void * consume(void* threadarg) { int i; for(i=0;i Fall 2016 Operating Systems 72 Producer Consumer - Mutex - Main - Attempt 2 int main() { pthread_t producer, consumer; //initialize mutex and condition variables pthread_mutex_init(&pc_mutex, NULL); pthread_cond_init(&cond_availData, NULL); /* Initialize consumer condition variable */ pthread_cond_init(&cond_availSpace, NULL); /* Initialize producer condition variable */ //create producer thread pthread_create(&producer, NULL, produce, NULL); //create consumer thread pthread_create(&consumer, NULL, consume, NULL); //wait for threads to finish pthread_join(producer, NULL); pthread_join(consumer, NULL); //cleanup pthread_mutex_destroy(&pc_mutex); /*free up the mutex*/ pthread_cond_destroy(&cond_availData); /* Free up consumer condition variable */ pthread_cond_destroy(&cond_availSpace); /* Free up producer condition variable */ //exit main thread pthread_exit(NULL); } Fall 2016 Operating Systems 73 Outline • Interprocess Communication • Race Conditions • Critical Regions • Mutual Exclusion • Hardware Solution • Case Study: Producer Consumer • Semaphores • Mutex and Condition Variables • More Mutual Exclusion Mechanisms Fall 2016 Operating Systems 74 Monitors • Why use a higher-level synchronization primitive such as monitors? • A monitor is a collection of: procedures, variables, and data structures • Processes cannot access the monitor’s data structures • Processes can only call the monitor procedures • Only one process can be active in a monitor at any instant • therefore, mutual execution is guaranteed • Condition variables with two operations wait and signal are introduced Fall 2016 Operating Systems 75 Implementing Monitors • The compiler is aware of the monitors and therefore it guarantees: • only one process can be executing in the monitor at any time • the compiler uses primitives such as mutex and binary semaphores to implement monitors • a process calling a signal must exit the monitor, therefore a signal can only appear at the end of a procedure • Note: condition variables are not counters and therefore signals is lost if no processes are waiting for it • Note: wait and signal are not similar to sleep and wakeup that we have used in the first solution of producer/consumer problem Fall 2016 Operating Systems 76 Structure of a Monitor Credit: William Stallings, Operating Systems: Internals and Design Principles, 7th ED Fall 2016 Operating Systems 77 Producer Consumer - Monitors Fall 2016 Operating Systems 78 Producer Consumer - Monitors Fall 2016 Operating Systems 79 Message Passing • Suitable for distributed systems • Two primitives that are implemented through system calls: • send(destination, &message): sends a message to destination • receive(source, &message): receives a message from source Fall 2016 Operating Systems 80 Design Issues for Message-Passing Systems • A receive can block waiting for a message from the source, or return with error if a message is not ready • What to do about lost messages • use acknowledgment • duplicate messages • Using mailbox to hold the messages • If both send and receive are blocking, this strategy is called rendezvous Fall 2016 Operating Systems 81 Producer Consumer - Message Passing Fall 2016 Operating Systems 82 Thank You!