160 likes | 183 Views
This presentation by Antonio Maiorano and Paul Di Marco discusses the concept of monitors, their key attributes, and how they can be accessed by only one thread at a time. It also covers the use of condition variables and provides solutions for avoiding deadlock. The presentation emphasizes the importance of using higher-level constructs and stress testing code for deadlock prevention.
E N D
Monitor Review and Deadlock! Presented by: Antonio Maiorano Paul Di Marco
Monitors • One can think of a monitor as another Abstract Data Type – like a structure or class – with functions and private data • The key attribute of a monitor is that it can be accessed by only one thread at a time
Monitor call: … myMonitor.Foo() … Monitors are simpler! Analogous call w/o Monitors: … mutex.wait(); myObject.Foo(); mutex.signal(); … Monitor Analogy A monitor object can be thought of as an object where each access to it is protected by a mutex:
A Simple Monitor monitor SharedBalance { private int balance; public SharedBalance(int amt) {balance = amt;} public credit(int amt) {balance += amt;} public debit(int amt) {balance -= amt;} }
Show me the money • Let’s say we only allow someone to complete a debit transaction when there is enough money to take: SharedBalance::debit(int amt) { while(balance < amt) { } // wait for the cash balance -= amt; }
Whoops! • This won’t work if a debit() call occurs when there is not enough money: • debit() waits for someone to credit the account • credit() can’t run because debit is already executing in the monitor! • > DEADLOCK! • We need to use Condition Variables…
Condition Variables • Condition variables are used when: • a thread running in a monitor • encounters a condition that is not satisfied, • which can only be satisfied by another thread • Ours has 3 operations: • wait() - block on a variable, give up monitor • signal() - wake up a thread blocked on this • queue() - asks “are there any threads blocked on you?”
Condition Variables • You wait on a c.v. when you want to get another thread to do something for you. This is what happens when you wait(): • It temporarily blocks you, • Hands over “ownership” of the monitor you are running in to another thread • Gives you back the “ownership” of the monitor later on…
Regaining the Monitor • There are two schemes for deciding when the blocked thread will regain the monitor: • Immediately, as soon as another thread signals the condition variable, or • Later on, when the thread (that signaled) finishes executing inside the monitor
Show me the money already! • Using a new member variable condVar: SharedBalance::credit(int amt) { balance += amt; condVar.signal(); } SharedBalance::debit(int amt) { while(balance < amt) { condVar.wait(); } balance -= amt; }
Thread 1: alpha.Wait(); beta.Wait(); DoSomething(); beta.Signal(); alpha.Signal(); Thread 2: beta.Wait(); alpha.Wait(); DoSomething(); alpha.Signal(); beta.Signal(); Deadlock with Semaphores Semaphore alpha = new Semaphore(1); Semaphore beta = new Semaphore(1);
Thread 1: alpha.Wait(); beta.Wait(); DoSomething(); beta.Signal(); alpha.Signal(); Thread 2: alpha.Wait(); beta.Wait(); DoSomething(); beta.Signal(); alpha.Signal(); A Solution Semaphore alpha = new Semaphore(1); Semaphore beta = new Semaphore(1);
Things to Note • Semaphores are powerful low-level synchronization tools they can be difficult to use • Guidelines: • Enforce strict coding standards • Use higher-level constructs if they’re available (i.e. AND-synchronization) • Stress test your code for deadlock
Thread 1: // Wait for var to be set alpha.Wait(); // Use var DoSomething(var); // We’re done with var beta.Signal(); Thread 2: // Set var var = InitVal(); // Let other thread use it alpha.Signal(); // Wait until it’s used beta.Wait(); Deadlock with Events int var; // Global shared variable Event alpha = new Event(0); Event beta = new Event(0);
A Couple of Solutions • Impose a total ordering system: Use a semaphore to ensure Thread 1 starts before Thread 2 OR • Use semaphores instead of events because what happens in the past counts (recall: semaphores are passive, events are active)
Things to Note • With events, deadlock often occurs due to timing dependencies • Must ensure that threads start in order if timing is important • Consider using semaphores instead of events – use events only when the future is important, not the past