210 likes | 293 Views
Learn about race conditions, critical sections, mutexes, and thread synchronization in POSIX programming. Understand how to avoid data conflicts and implement efficient synchronization methods.
E N D
Today • Posix Threads Howto Leftovers • Intro to Synchronization Issues
Today’s Objectives • Explain how multiple threads can get into trouble using shared data. • Give an example. • Define mutual exclusion, critical sections, and race conditions. • Explain why it’s not easy to ensure mutual exclusion between threads, and give an example of how a mutex might be implemented in an OS. • Write multi-threaded programs that use POSIX mutexes for synchronization.
Admin • Quiz 4 next Thursday
The Trouble With Threads • Concurrent access to shared data? • Is everyone just reading? We’re ok. • Is someone writing? Unsafe.
Concepts • Situations where two or more processes are reading or writing some shared data and the final result depends on who runs when are called race conditions. • The section of code where a thread accesses a shared resource non-atomically is known as a critical section. • Today is about learning some tools that we can use to synchronize access between threads to stay safe.
Mutual Exclusion • We wish to prohibit multiple threads from accessing shared data at the same time • We call this mutual exclusion • Shorthand: mutex • The design of primitives to enforce mutual exclusion is a central part of OS design • Take 5103 and you get to implement these primitives yourself
Avoiding Race Conditions • Four conditions to avoid race conditions: • No two threads simultaneously in critical region • No assumptions made about speeds or numbers of CPUs • No thread running outside its critical region may block another thread • No thread must wait forever to enter its critical region
Bad Solution 1 • Disable Interrupts • How does this help? • Do we really want to allow user processes to disable interrupts? (what are the consequences in a multi-user system?) • Will this work on a multi-CPU system? • Conclusion: The OS may wish to disable interrupts as part of a mutex implementation
Bad Solution 2 • Lock Variable int lock = 0while (lock)lock=1do critical section lock=0 • What’s wrong with this solution? Remember that context switches can happen at any time.
Hardware Support Helps • Test and Set Lock instruction • Example: TSL RX, LOCK • All at once: • read the contents of LOCK into register RX • Store nonzero value in LOCK • How can we use this crazy instuction?
Priority Inversion • Hmm...one more problem • enter_region guarantees mutex, but it uses busy waiting. • Inefficient, and... • The priority inversion problem • Two processes, H and L (high and low priority). H runs whenever it is in “ready” state, L never runs when H is ready. • L holds a lock • H wakes up from an I/O operation and decides that it wants that lock. • (Thus, L is really the highest-priority process here)
Achieving Mutual Exclusion • Finding critical sections in code can be hard (debugging typically won’t work) • Luckily, the mechanisms built into UNIX make *implementing* mutex pretty easy. • Some possibilities • File locks • Pipes • Semaphores • POSIX mutex
POSIX Mutex • What is a POSIX Mutex? • It’s a variable that can be either locked or unlocked. • If the mutex is locked, then there is a thread that is said to “hold” the mutex. • Meant to be used for short periods of time.
Many Threads • So what if there are many threads that all want access to the same data? • POSIX mutex maintains a queue of processes that wish to hold the mutex. • POSIX does not guarantee the order in which processes in the queue obtain the mutex.
Mutex Interface • pthread_mutex_init • pthread_mutex_destroy • pthread_mutex_lock • pthread_mutex_trylock • pthread_mutex_unlock