
color Application-level concurrency:Deadlock, Lifelock, Starvation Summary of Yesterday's lecture We learned about: • Learned how to define an optimistic concurrency control strategy. • Discussed where such strategies are useful. • Learned about the compare-and-set (or compare-and-swap or CAS) and how to describe its operation using pseudo-code. • Learned what the Atomic classes in Java's atomic package do, where they can be used. • Talked about the ABA problem and seen examples of where it can arise. • Discussed the use of stamped references to address this problem. Deadlocks • Problematic in Java applications, because the only way to resolve a dead- lock is to terminate the application. • Necessary and sufficient deadlock conditions (E. G. Coffman etal. System Deadlocks. Computing Surveys, Vol. 3, No. 2, June 1971) { Mutual exclusion: Resources cannot be shared: One thread holds a resource that cannot be shared by another thread concurrently. { Hold and wait condition: There is a thread that holds a non-sharable resource and waits for another non-sharable resource that is held by another thread. { No-preemptive condition: Threads holding non-sharable resources have to give them up voluntarily - they cannot be forced from outside to release the resource. { Circular wait condition: Threads waiting for resources in a cyclic dependency. Deadlock examples • Dining Philosophers Problem, Drinking Philosophers Problem • Deadly embrace Deadlock.java 1 • Dynamic lock order deadlock. DeadlockingBankAccount.java • Deadlock avoidance using lock hashes and tie braking locks to enforce ordering constraints. Deadlocks The following is deadlock prone when executed concurrently: public class DeadlockProne{ Object lock1= new Object(); Object lock2= new Object(); public void transfer12(){ synchronized(lock1){ synchronized(lock2){ doSomeWork(); } } } public void transfer21(){ synchronized(lock2){ synchronized(lock1){ doSomeMoreWork(); } } } } Deadlock avoidance private static final Object tieLock= new Object(); public void transferFunds(Account from, Account to, int amount){ class Helper{ public void transfer(){ from.debit(amount); to.credit(amount);} } int fromHash= System.identityHashCode(from); int toHash= System.identityHashCode(to); if(fromHash< toHash){ synchronized(fromHash){synchronized(toHash){new Helper.transfer();}} } else if(toHash< fromHash){ synchronized(toHash){synchronized(fromHash){new Helper.transfer();}} } else{ synchronized(tieLock){ synchronized(toHash){synchronized(fromHash){new Helper.transfer();}} } } Livelock • While not blocked, threads still cannot make progress. 2 • Example: Transactional messaging applications: { Transaction that cannot be processed successfully is rolled back and put back to waiting queue to be retried later. { Buggy error handler that treats this as a recoverable problem causes this loop not to terminate • Another possible livelock: Cooperating thread change state in response to others in a way that inhibits progress LiveLockAtDinnertime.java • Possible scenario: Threads try to access shared resource, detect collision, and try again after fixed time. • Possible solution: Introduce randomness. Starvation • Failure to acquire resources for extended times, potentially forever. • Most contended resource in practice: CPU cores • Potential issue with non-standard thread scheduling priorities StarvingBankAccount.java • JVMs do not make any guarantees about implementation of thread priori- ties: Could be dealt with by host OS, or ignored entirely, hence, behaviour is platform dependent • Advice: Do not fiddle with priorities without good reason! { A good reason to do so anyway could be: Background tasks cause GUI responsiveness issues. { Setting the priority below Thread.NORM PRIORITY may solve respon- siveness problem. Make sure there is no issue if this background tasks suffers from starvation! Starvation Due to unfair locking: • Failure to acquire locks for extended times, potentially forever. • Lock acquisition process may be highly unfair • Example: tryLock() in ReentrantLock has barging semantics: Lock is often acquired instantly, even if a large number of threads blocked on lock(). 3 • Synchronized statements make no guarantees about fairness Wait set starvation: • Waiting on a monitor condition for extended times, potentially forever. • Likely if using notify() instead of notifyAll() to signal. • There is no control over which thread is proceeding to lock acquisition, so there may be threads never leaving the condition queue. Testing threaded applications Guidelines: • First test your code for correctness when executed sequentially, e.g., run only 1 thread at a time: Testing concurrency issues in isolation is hard enough! Concurrency strongly increases the number of possible execution paths. • Difficult to test: Infrequent race conditions or deadlocks. • Approaches to reveal these: 1. Test on different platforms and with different JVMs. 2. Create high contention, i.e., increase the number of threads as much as practical. 3. Things happen at context switches: Instrument code with Thread.yield() or Thread.sleep() methods at critical locations methods to encour- age problematic interference. Summary Today we have discussed: • Deadlocks: static and dynamic lock ordering deadlocks • Livelock and Starvation • Testing concurrent software 4.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages4 Page
-
File Size-