Download presentation
Presentation is loading. Please wait.
1
CS 3214 Introduction to Computer Systems
Lecture 19 Godmar Back
2
Announcements Read Chapter 13 Exercise 10 due Nov 3 (today)
(ignore stuff about file web servers for now) Exercise 10 due Nov 3 (today) Exercise 11 is out – very structured exercise Due Nov 12 (but should not take this long; don’t procrastinate) Will give feedback on whether Project 3 meets minimum requirements before weekend Will use the tests you provided Project 4 out by Thursday CS 3214 Fall 2009 9/12/2018
3
Threads and Processes Part 8
Some of the following slides are taken with permission from Complete Powerpoint Lecture Notes for Computer Systems: A Programmer's Perspective (CS:APP) Randal E. Bryant and David R. O'Hallaron Part 8 Threads and Processes CS 3214 Fall 2009 9/12/2018
4
Condition Variables - Intro
Besides (and perhaps more so) than semaphores, condition variables are another widely used form to implement ‘signaling’ kinds of coordination/synchronization In POSIX Threads, Java, C# Based on the concept of a Monitor ADT that combines protected access to state and signaling Confusing terminology alert: Word ‘signal’ is overloaded 3 times Semaphore signal (V(), “up”, “post”) Monitor/Condition variable signal (“signal”, “notify”) Unix signals Word ‘wait’ is overloaded Semaphore wait (P(), “down”) Monitor/Condition variable wait Unix wait() for child process CS 3214 Fall 2009 9/12/2018
5
Monitors A monitor combines a set of shared variables & operations to access them Think of a Java class with no public fields & all public methods carrying the attribute ‘synchronized’ A monitor provides implicit synchronization (only one thread can access private variables simultaneously) Single lock is used to ensure all code associated with monitor is within critical section A monitor provides a general signaling facility Wait/Signal pattern (similar to, but different from semaphores) May declare & maintain multiple signaling queues CS 3214 Fall 2009 9/12/2018
6
Monitors (cont’d) Classic monitors are embedded in programming languages Invented by Hoare & Brinch-Hansen 1972/73 First used in Mesa/Cedar Xerox PARC 1978 Adapted version available in Java/C# (Classic) Monitors are safer than semaphores can’t forget to lock data – compiler checks this In contemporary C, monitors are a synchronization pattern that is achieved using locks & condition variables Helps to understand monitor abstraction to use it correctly CS 3214 Fall 2009 9/12/2018
7
Infinite Buffer w/ Monitor
monitor buffer { /* implied: struct lock mlock;*/ private: char buffer[]; int head, tail; public: produce(item); item consume(); } buffer::produce(item i) { /* try { lock_acquire(&mlock); */ buffer[head++] = i; /* } finally {lock_release(&mlock);} */ } buffer::consume() return buffer[tail++]; Monitors provide implicit protection for their internal variables Still need to add the signaling part CS 3214 Fall 2009 9/12/2018
8
Condition Variables Used by a monitor for signaling a condition
a general (programmer-defined) condition, not just integer increment as with semaphores Somewhat weird: the condition is actually not stored in the variable – it’s typically some boolean predicate of monitor variables, e.g. “buffer.size > 0” the condition variable itself is better thought of as a signaling queue Monitor can have more than one condition variable Three operations: Wait(): leave monitor, wait for condition to be signaled, reenter monitor Signal(): signal one thread waiting on condition Broadcast(): signal all threads waiting on condition CS 3214 Fall 2009 9/12/2018
9
Condition Variables as Queues
Region of mutual exclusion Enter Exit Wait Signal A condition variable’s state is just a queue of waiters: Wait(): adds current thread to (end of queue) & block Signal(): pick one thread from queue & unblock it Broadcast(): unblock all threads Note on style: best practice is to leave monitor only once, and near the procedure’s entry. CS 3214 Fall 2009 9/12/2018
10
Bounded Buffer w/ Monitor
monitor buffer { condition items_avail; condition slots_avail; private: char buffer[]; int head, tail; public: produce(item); item consume(); } buffer::produce(item i) { while ((tail+1–head)%CAPACITY==0) slots_avail.wait(); buffer[head++] = i; items_avail.signal(); } buffer::consume() while (head == tail) items_avail.wait(); item i = buffer[tail++]; slots_avail.signal(); return i; CS 3214 Fall 2009 9/12/2018
11
Bounded Buffer w/ Monitor
monitor buffer { condition items_avail; condition slots_avail; private: char buffer[]; int head, tail; public: produce(item); item consume(); } buffer::produce(item i) { while ((tail+1–head)%CAPACITY==0) slots_avail.wait(); buffer[head++] = i; items_avail.signal(); } buffer::consume() while (head == tail) items_avail.wait(); item i = buffer[tail++]; slots_avail.signal(); return i; Q1.: How is lost update problem avoided? lock_release(&mlock); block_on(items_avail); lock_acquire(&mlock); Q2.: Why while() and not if()? CS 3214 Fall 2009 9/12/2018
12
cond_signal semantics
cond_signal keeps lock, so it leaves signaling thread in monitor waiter is made READY, but can’t enter until signaler gives up lock There is no guarantee whether signaled thread will enter monitor next or some other thread will (who may be already waiting!) so must always use “while()” when checking condition – cannot assume that condition set by signaling thread will still hold when monitor is reentered by signaled thread This semantics is also referred to as “Mesa-Style” after the system in which it was first used POSIX Threads, Java, and C# use this semantics CS 3214 Fall 2009 9/12/2018
13
Condition Variables vs. Semaphores
Signals are lost if nobody’s on the queue (e.g., nothing happens) Wait() always blocks Semaphores Signals (calls to V() or sem_post()) are remembered even if nobody’s current waiting Wait (e.g., P() or sem_wait()) may or may not block CS 3214 Fall 2009 9/12/2018
14
Monitors in C POSIX Threads as well as many custom environments
No compiler support, must do it manually must declare locks & condition vars must call pthread_mutex_lock/unlock when entering & leaving the monitor must use pthread_cond_wait/pthread_cond_signal to wait for/signal condition Note: pthread_cond_wait(&c, &m) takes monitor lock as parameter necessary so monitor can be left & reentered without losing signals pthread_cond_signal() does not leaving room for programmer error! CS 3214 Fall 2009 9/12/2018
15
Monitors in Java synchronized block means
class buffer { private char buffer[]; private int head, tail; public synchronized produce(item i) { while (buffer_full()) this.wait(); buffer[head++] = i; this.notifyAll(); } public synchronized item consume() { while (buffer_empty()) i = buffer[tail++]; return ; synchronized block means enter monitor execute block leave monitor wait()/notify() use condition variable associated with receiver Every object in Java can function as a condition variable (just like it can function as a lock) More restrictive than Pthreads/C which allow multiple condition variables (signaling conditions) to be used in connection with a lock protecting state CS 3214 Fall 2009 9/12/2018
16
import java.util.concurrent.locks.*;
class buffer { private ReentrantLock monitorlock = new ReentrantLock(); private Condition items_available = monitorlock.newCondition(); private Condition slots_available public /* NO SYNCHRONIZED here */ void produce(item i) { monitorlock.lock(); try { while (buffer_full()) slots_available.await(); buffer[head++] = i; items_available.signal(); } finally { monitorlock.unlock(); } } /* consume analogous */ Monitors in Java, Take 2 Previous slide (bounded buffer) is actually an example of where Java’s built-in monitors suck Needed “notifyAll()” to make sure one at least one of the right kind of threads was woken up Unacceptably inefficient Use java.util.concurrent.- locks.Condition instead in case where multiple condition queues are needed CS 3214 Fall 2009 9/12/2018
17
A ReadWrite Lock Implementation
struct lock mlock; // protects rdrs & wrtrs int readers = 0, writers = 0; struct condvar canread, canwrite; void read_lock_acquire() { lock_acquire(&mlock); while (writers > 0) cond_wait(&canread, &mlock); readers++; lock_release(&mlock); } void read_lock_release() { if (--readers == 0) cond_signal(&canwrite); void write_lock_acquire() { lock_acquire(&mlock); while (readers > 0 || writers > 0) cond_wait(&canwrite, &mlock); writers++; lock_release(&mlock); } void write_lock_release() { writers--; ASSERT(writers == 0); cond_broadcast(&canread); cond_signal(&canwrite); Note: this is a naïve implementation that may lead to livelock – no guarantees a reader or writer ever enters the locked section even if every threads eventually leaves it CS 3214 Fall 2009 9/12/2018
18
Summary Semaphores & Condition Variables provide signaling facilities
Condition variables are loosely based on “monitor” concept Java/C# provide syntactic sugar Semaphores have “memory” But require that # of signals matches # of waits Good for rendez-vous, precedence constraints – if problem lends itself to semaphore, use one Always use idiomatic “while (!cond) *_wait()” pattern when using condition variables (in C) or Object.wait() (in Java) CS 3214 Fall 2009 9/12/2018
19
Race Detection Tools A number of tools help to detect race conditions (Helgrind, Intel Thread Checker) Dynamic analysis tools Typically based one or both of these approaches: Locksets: detect if no lock is consistently held when a given variable x is accessed “Happens-before” relationship: (intuition) if we can’t prove that access A must happen before B due to the synchronization the programmer used, then it’s a race; example: All accesses before a thread is started “happen before” all accesses by a thread; and these accesses “happen before” all accesses done after the thread is joined Typically do not detect atomicity violations CS 3214 Fall 2009 9/12/2018
20
Deadlock (Definition)
A situation in which two or more threads or processes are blocked and cannot proceed “blocked” either on a resource request that can’t be granted, or waiting for an event that won’t occur Possible causes: resource-related or communication-related Cannot easily back out CS 3214 Fall 2009 9/12/2018
21
Resource Deadlock Canonical Example
pthread_mutex_t A; pthread_mutex_t B; … pthread_mutex_lock(&A); pthread_mutex_lock(&B); pthread_mutex_unlock(&B); pthread_mutex_unlock(&A); pthread_mutex_lock(&B); pthread_mutex_lock(&A); … pthread_mutex_unlock(&A); pthread_mutex_unlock(&B); A B Thread 1 Thread 2 CS 3214 Fall 2009 9/12/2018
22
Using Lock Ordering to Avoid Deadlock
acquire locks in same order void transferTo(account *this, account *that, int amount) { if (this < that) { pthread_mutex_lock(&this->lock); pthread_mutex_lock(&that->lock); } else { } /* rest of function */ Tricky in Java when synchronized is used: System.identityHashcode provides ordering of arbitrary objects CS 3214 Fall 2009 9/12/2018
23
Deadlocks, more formally
4 necessary conditions Exclusive Access Hold and Wait No Preemption Circular Wait Aka Coffman conditions Note that cond 1-3 represent things that are normally desirable or required Strategies involve Detect & break deadlocks Prevent Avoid CS 3214 Fall 2009 9/12/2018
24
Deadlocks Detection Uses Resource Allocation Graph
For single-item resources cycle in this graph is necessary & sufficient for resource deadlock to exist Some systems have deadlock detection built-in But usually an option that must be turned on Resource Allocation Graph R → P Assignment P → R Request R1 P1 P2 P3 P4 R2 R3 R4 CS 3214 Fall 2009 9/12/2018
25
Deadlock Recovery Can attempt to revoke resources, kill some participants, or (worst case) kill all participants to break cycle CS 3214 Fall 2009 9/12/2018
26
Deadlock Prevention Idea: remove a necessary condition
C1: (do not require) exclusive access C2: (don’t) hold and (then) wait C3: (allow) preemption/revocation C4: (don’t) create cycles: lock ordering! Deadlock is tricky because it’s not always clear/possible how to remove or eliminate these conditions, particularly C4 Distinct from “Deadlock Avoidance” Well studied, but rarely used technique in which necessary conditions aren’t removed, but resource allocations are managed in a way that avoids deadlock CS 3214 Fall 2009 9/12/2018
27
Deadlock vs. Starvation vs. Livelock
No matter which policy the scheduler chooses, there is no possible way for processes to make forward progress Starvation: There is a possible way in which threads can make possible forward progress, but the scheduler doesn’t choose it Example: strict priority scheduler will never scheduler lower priority threads as long as higher-priority thread is READY Example: naïve reader/writer lock: starvation may occur by “bad luck” Livelock: Threads are continually engaged in tasks that prevent them from making progress on their actual goals, such as reattempting to acquire locks, or responding to each other’s signals CS 3214 Fall 2009 9/12/2018
28
Informal uses of term `deadlock’
4 Coffman conditions apply specifically to deadlock with definable resources Term deadlock is sometimes informally used to also describe situations in which not all 4 criteria apply See interesting discussion in Levine 2003, Defining Deadlock Consider: When two trains approach each other at a crossing, both shall come to a full stop and neither shall start up again until the other has gone. Does it meet the 4 conditions? However, even under informal/extended view, not all “lack of visible progress” situations can reasonably be called deadlocked e.g., an idle system is not usually considered deadlocked CS 3214 Fall 2009 9/12/2018
29
Summary Deadlock: Strategies to deal with:
4 necessary conditions: mutual exclusion, hold-and-wait, no preemption, circular wait Strategies to deal with: Prevention: remove one of 4 necessary conditions Detect & recover Avoidance: if you can’t do that, avoid deadlock by being conservative CS 3214 Fall 2009 9/12/2018
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.