430 likes | 526 Views
Introduction to Systems Programming Lecture 4. Inter-Process / Inter-Thread Communication. Stand-Alone Solutions (cont.). Reminder: Mutual Exclusion. Avoid race conditions : make sure that shared variables are not read and written “at the same time”.
E N D
Introduction to Systems Programming Lecture 4 Inter-Process / Inter-Thread Communication
Reminder: Mutual Exclusion • Avoid race conditions: make sure that shared variables are not read and written “at the same time”. • Not always a shared variable. In general – acritical region.
Conditions for Mutual Exclusion • [Safety] No two processes/threads simultaneously in critical region. • [Criticality] No process/thread running outside its critical region may block another process/thread. • [Liveness] No process/thread must wait forever to enter its critical region. No assumptions made about speed of CPU or scheduling.
Solutions that Didn’t Work • Simple “lock” shared variable • Strict alternation • First correct solution by Dekker, 1965 • Simpler solution by Petersen, 1981
Sketch of Thread Int myID; // 0 or 1 While (TRUE) { enter_region(myID); // return when OK to enter critical_region(); // do work in critical region leave_region(myID); }
Peterson's Algorithm for Mutual Exclusion /* my turn to wait */
How does it work • If nobody in critical region, 0 tries to enter: • turn == process (== 0), so should wait - • … but interested[1] != TRUE exit spin-lock [Criticality] condition holds • If process 0 in critical region and 1 tries to enter: • turn == process (== 1), so should wait - • … and interested[0] == TRUE 1 stuck in spin-lock [Safety] condition holds in this case
Peterson with Race Condition? • If both try to enter at same time • Interested[0] ==1, Interested[1] == 1 • Both write “turn”. Suppose 1 writes last. • For 1, turn == process stuck in spin-lock • For 0, turn != process exits spin-lock • turn used like in alternating solution, but: • turn == 1 process 0 allowed to enter. • [Safety] holds
Mutual Exclusion with Hardware TSL instruction (test-and-set-lock): TSL RX, lock • RX is a register, lock is a variable in memory • Does 2 things: • RX = lock // copy contents of lock into RX • Lock = 1 // set the lock • Atomic: no interrupt “in the middle” of TSL.
Using the TSL instruction Use the busy-wait “lock” algorithm that failed in software
Priority Inversion with Busy Waiting Assumption: static priority scheduling • 2 threads: H with high priority, L with low. • L in critical region • H tries to enter, stuck in spin-lock • H has high priority: keeps getting scheduled. • L never gets scheduled never exists critical region. • H remains stuck.
The OS should help • Use system calls to implement enter_region() • Instead of busy-wait, the OS would put the calling thread in BLOCKED state if cannot enter. • Advantage: other threads can run, no CPU waste, helps avoid priority inversion.
Producer-Consumer Problem • Two threads share a buffer of size N.(a FIFO Queue from data-structures course) • The producer thread puts items in buffer. • The consumer thread takes items out of buffer. • Producer should block when buffer is full • Consumer should block when buffer is empty
Sleep/Wakeup Mechanism • A simple inter-process communication primitive. • Two system calls: • Sleep(): make thread blocked until another wakes it. • Wakeup(thread_id): wake a sleeping thread
Producer/Consumer with Sleep-Wakeup 3. Consumer not asleep: Wakeup lost /* local to the thread */ 1. count == 0, consumer scheduled first 2. Interrupt
What went wrong? • Race condition on count variable. • Wakeup sent to process that is not asleep – lost. • Consumer remains asleep forever. • Producer fills buffer, and goes to sleep (forever).
Semaphores • Improved OS mechanism • Invented by E. Dijkstra, 1965. • Idea: use an integer variable to count the number of future wakeup() calls.
Semaphore Operations • Down(semaphore): • If semaphore == 0, BLOCK (sleep) // when unblocked semaphore is > 0 • semaphore-- The down operation is atomic!! • Up(semaphore) • semaphore++ • If there are processes blocked on semaphore, one is chosen to complete its down operation.
Implementing Semaphores • Semaphores are implemented via system calls • Usually, OS disables interrupts during the Down() and Up() operations to avoid race conditions and guarantee atomicity.
Semaphores for Mutual Exclusion A 0/1 semaphore a binary semaphore. int mutex = 1; While (TRUE) { down(mutex); critical_region(); up(mutex); }
Two Types of Semaphores • The binary semaphore “mutex” is used for mutual exclusion. • The counting semaphores “full” and “empty” are for synchronization.
Semaphores in Win2000 • Semaphores are kernel objects. • CreateSemaphore() • WaitForSingleObject() • This behaves like down() on a semaphore. • ReleaseSemaphore() • This is the up() operation.
Mutexes in Win2000 • Mutexes are kernel objects. • CreateMutex() • WaitForSingleObject() • This behaves like down() (also called mutex_lock()) on a mutex. • ReleaseMutex() • This is the up() (also called mutex_unlock() ) operation.
Inter-Process Communication (Without shared memory)
More general communication • What if processes need to communicate? no shared memory • What if processes reside on separate computers?no shared OS • Need to work through a network connection
Message Passing Simplified mechanism with 2 system calls: • send(destination, message) • Sends a message to destination • receive(source, message) • Receives a message from source • Source can be ANY if receiver does not care • BLOCK if no message available (or return with error code)
Producer-Consumer with Message Passing • Assumptions: • Messages sent but not received are buffered by OS. • Messages are received in the order they are sent. • Consumer sends Producer N “empty” messages. • When producer has item, it receives a message and sends the item.
Classical OS Problems Dining Philosophers
Dining Philosophers • Philosophers eat/think • Eating needs 2 forks • Pick one fork at a time • How to prevent deadlock
Why is this bad? • Suppose all philosophers take left fork at the same time. • All get stuck trying to take right fork. • This is called deadlock.
A fix? • After taking left fork, check if right fork available. • If not put the left fork down, wait, and repeat. • Not good: if all start together, they repeat forever: • Pick left fork • Put it down, wait • This is called livelock.
A Randomized Solution while (TRUE) { if (take_fork(i)) { if (take_fork(i+1 % N)) break; //success – have both forks else release_fork(i); } wait(random()); }
Properties of the Randomized Solution • Livelock can only occur if random numbers are the same for all philosophers. • High probability of no-livelock – • … but livelock is possible. • This is what Ethernet does.
A Safe Solution • Protect the procedure with a mutex. • No deadlock – • … but only one philosopher eating at a time. • With 5 philosophers, 2 should be able to eat at the same time.
Notes • Mutex is only over test() and state manipulations, not over eat(). • Up(s[i]) can be used from i to itself! • Deadlock-free, and allows parallelism
Concepts for review • Peterson’s algorithm • TSL instruction (test-and-set-lock) • Priority Inversion • Producer-Consumer Problem • Sleep-Wakeup • Semaphore • Binary semaphore / mutex • Deadlock • Dining philosophers