CMSC 433 Programming Language Technologies and Paradigms. Spring 2013

Similar documents
Lecture 10 State dependency

CMSC 433 Programming Language Technologies and Paradigms. Composing Objects

The Dining Philosophers Problem CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages. The Dining Philosophers Problem

CMSC 330: Organization of Programming Languages. Threads Classic Concurrency Problems

CS11 Java. Fall Lecture 7

CMSC 330: Organization of Programming Languages

Overview. CMSC 330: Organization of Programming Languages. Concurrency. Multiprocessors. Processes vs. Threads. Computation Abstractions

COMPSCI 230 Threading Week8. Figure 1 Thread status diagram [

Part IV Other Systems: I Java Threads

Java Threads. COMP 585 Noteset #2 1

Need for synchronization: If threads comprise parts of our software systems, then they must communicate.

COMP31212: Concurrency A Review of Java Concurrency. Giles Reger

Overview. Processes vs. Threads. Computation Abstractions. CMSC 433, Fall Michael Hicks 1

Week 7. Concurrent Programming: Thread Synchronization. CS 180 Sunil Prabhakar Department of Computer Science Purdue University

Java Threads Vs Processes. CS Concurrent Programming. Java Threads. What can a thread do? Java Concurrency

Advanced Concepts of Programming

Monitors; Software Transactional Memory

Only one thread can own a specific monitor

Java Threads. Introduction to Java Threads

Concurrency in Java Prof. Stephen A. Edwards

CS 455: INTRODUCTION TO DISTRIBUTED SYSTEMS [THREADS] Frequently asked questions from the previous class survey

Computation Abstractions. Processes vs. Threads. So, What Is a Thread? CMSC 433 Programming Language Technologies and Paradigms Spring 2007

Monitors; Software Transactional Memory

Models of concurrency & synchronization algorithms

Java Monitors. Parallel and Distributed Computing. Department of Computer Science and Engineering (DEI) Instituto Superior Técnico.

CSE332: Data Abstractions Lecture 22: Shared-Memory Concurrency and Mutual Exclusion. Tyler Robison Summer 2010

Threads Chate Patanothai

Question Points Score Total 100

Recap. Contents. Reenterancy of synchronized. Explicit Locks: ReentrantLock. Reenterancy of synchronise (ctd) Advanced Thread programming.

Lecture 10: Introduction to Semaphores

CMSC 330: Organization of Programming Languages

CS61B, Spring 2003 Discussion #17 Amir Kamil UC Berkeley 5/12/03

Problems with Concurrency. February 19, 2014

Chapter 32 Multithreading and Parallel Programming

CS5460: Operating Systems

Threads and Parallelism in Java

Monitors & Condition Synchronization

What's wrong with Semaphores?

CS 162 Operating Systems and Systems Programming Professor: Anthony D. Joseph Spring 2004

Computation Abstractions. CMSC 330: Organization of Programming Languages. So, What Is a Thread? Processes vs. Threads. A computer.

Synchronization. CS 475, Spring 2018 Concurrent & Distributed Systems

Component-Based Software Engineering

Lecture 9: Introduction to Monitors

CSCI 5828: Foundations of Software Engineering

Synchronization in Concurrent Programming. Amit Gupta

CS 351 Design of Large Programs Threads and Concurrency

wait with priority An enhanced version of the wait operation accepts an optional priority argument:

CSCD 330 Network Programming

CSCD 330 Network Programming

RACE CONDITIONS AND SYNCHRONIZATION

Chair of Software Engineering. Java and C# in depth. Carlo A. Furia, Marco Piccioni, Bertrand Meyer. Java: concurrency

Introduction to Locks. Intrinsic Locks

CMSC421: Principles of Operating Systems

THREADS AND CONCURRENCY

5. Liveness and Guarded Methods

Contribution:javaMultithreading Multithreading Prof. Dr. Ralf Lämmel Universität Koblenz-Landau Software Languages Team

Multiple Inheritance. Computer object can be viewed as

Multi-threaded programming in Java

Threads and Locks, Part 2. CSCI 5828: Foundations of Software Engineering Lecture 08 09/18/2014

Programming Language Concepts: Lecture 13

27/04/2012. We re going to build Multithreading Application. Objectives. MultiThreading. Multithreading Applications. What are Threads?

Monitors & Condition Synchronization

Synchronized Methods of Old Versions of Java

Performance Throughput Utilization of system resources

Lecture 8: September 30

Thread-Local. Lecture 27: Concurrency 3. Dealing with the Rest. Immutable. Whenever possible, don t share resources

What is a Thread? Why Multicore? What is a Thread? But a fast computer runs hot THREADS AND CONCURRENCY. Concurrency (aka Multitasking)

Operating Systems. Lecture 4 - Concurrency and Synchronization. Master of Computer Science PUF - Hồ Chí Minh 2016/2017

Info 408 Distributed Applications Programming Exercise sheet nb. 4

Introduction to OS Synchronization MOS 2.3

CMSC 132: Object-Oriented Programming II. Threads in Java

CS18000: Programming I

Concurrent Queues, Monitors, and the ABA problem. Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

JFokus Finding And Solving Java Deadlocks

Synchronization 1. Synchronization

MultiThreading 07/01/2013. Session objectives. Introduction. Introduction. Advanced Java Programming Course

Introduction to Java Threads

CS 159: Parallel Processing

Advanced Java Programming Course. MultiThreading. By Võ Văn Hải Faculty of Information Technologies Industrial University of Ho Chi Minh City

Operating Systems CMPSCI 377 Spring Mark Corner University of Massachusetts Amherst

Threads and Java Memory Model

Programming Language Concepts: Lecture 11

Synchronization synchronization.

CMSC421: Principles of Operating Systems

COMP346 Winter Tutorial 4 Synchronization Semaphores

Module - 4 Multi-Threaded Programming

Atomic Variables & Nonblocking Synchronization

CSE 332: Data Structures & Parallelism Lecture 17: Shared-Memory Concurrency & Mutual Exclusion. Ruth Anderson Winter 2019

More Synchronization; Concurrency in Java. CS 475, Spring 2018 Concurrent & Distributed Systems

Concurrency: a crash course

CMSC 433 Spring 2013 Exam 1

Summary Semaphores. Passing the Baton any await statement. Synchronisation code not linked to the data

MCS-378 Intraterm Exam 1 Serial #:

Monitors & Condition Synchronisation

Threads Questions Important Questions

Principles of Software Construction: Concurrency, Part 2

Module 6: Process Synchronization. Operating System Concepts with Java 8 th Edition

Synchronising Threads

Concurrency COMS W4115. Prof. Stephen A. Edwards Spring 2002 Columbia University Department of Computer Science

Transcription:

1 CMSC 433 Programming Language Technologies and Paradigms Spring 2013 Wait / Notify / NotifyAll Optimistic Retries Composition Follow-up (the risk I mentioned) ReentrantLock, Wait, Notify, NotifyAll Some new tools for us java.util.concurrent.locks.reentrantlock this can be used to acquire and release a mutual-exclusion lock (lock() and unlock()) other than simply around a self-contained block of code. You can also use trylock() to get the lock if it s available without blocking if it s not..wait() releases a lock that the thread holds on that object only and has the thread basically go to sleep and get added to a wait set for that object until it s told that the lock is once again ready to be acquired when it is awoken, it is removed from the wait set and tries to reacquire the lock so that it can resume (this can be used from both intrinsic locks and ReentrantLock objects).notify() chooses one thread that is waiting for the lock (which you must hold when you call this method and should be about to release) and wakes it up to allow it to try to acquire the lock (note that another request could sneak in and steal it or it might not be free yet if you don t release it soon after notifying).notifyall() informs all threads waiting for the lock (which you must hold when you call this method) to wake up and try to acquire it this should be used if more than one thread might be waiting to avoid deadlock risks

2 Recall our robotic Japanese friends who could deadlock? static class JapaneseRobotBusinessFriends { String name; public JapaneseRobotBusinessFriends(String namein) { name = namein; public synchronized void bow( JapaneseRobotBusinessFriends mybussinessfriend) { System.out.println( name + " has bowed to " + mybussinessfriend.name ); mybussinessfriend.bowback(this); public synchronized void bowback( JapaneseRobotBusinessFriends bower) { System.out.println( name + " has returned the bow to " + bower.name ); What if we add a little more foresight to them? Have a volatile Boolean flag that you set when you are busy in some way. You are busy if: (a)you are in the process of bowing. (b)you are in the process of triggering the other robot to bow back at you. However, before actually starting to trigger the other robot to bow back at you, check to see if it is busy. If it is busy then set yourself as not busy and wait for the other robot to become available. When you wait, you give up your lock and go into standby mode until you are notified that the lock is available to grab again, or until a certain amount of time has passed.

3 Fixed robotic Japanese friends who don t deadlock! static class JapaneseRobotBusinessFriends { String name; volatile boolean busy = false; public JapaneseRobotBusinessFriends(String namein) { name = namein; public boolean isbusy() {return busy; public synchronized void bow(japaneserobotbusinessfriends mybussinessfriend) throws InterruptedException { busy = true; System.out.println(name + " has bowed to " + mybussinessfriend.name); while (mybussinessfriend.isbusy()) { busy = false; wait(1); busy = true; mybussinessfriend.bowback(this); busy = false; public synchronized void bowback(japaneserobotbusinessfriends bower) throws InterruptedException { busy = true; System.out.println(name + " has returned the bow to " + bower.name); busy = false; notifyall(); Can still deadlock with wait/notify use Consider a bounded buffer: public synchronized void put (Object elt) throws InterruptedException { while (elements.size() == maxsize) wait(); elements.add(elt); notify(); public synchronized Object take () throws InterruptedException { while (elements.size() == 0) wait(); Object elt = elements.get(0); elements.remove(0); notifyall(); return elt; Rance Cleaveland 2012 University of Maryland

4 Deadlock Scenario Time T1 T2 T3 T4 elements.size() Wait-set 0 take (w) 0 T1 1 take (w) 0 T1, T2 2 put 1 T2 3 put (w) 1 T2, T3 4 put (w) 1 T2, T3, T4 5 take (0) 0 T3, T4 6 take (w) 0 T1, T3, T4 7 take (w) 0 T1, T3, T4, T2 Legend op(w) operation waits / rewaits op(i) operation begun at time i completes op operation begins and completes without waiting Rance Cleaveland 2012 University of Maryland When classes use other objects In addition to making sure two threads aren t trying to interact with the same thread-unsafe object at the same time, or that invariants that cross objects are being properly guarded, there are some corner cases to consider, even with a thread-safe object. Some examples: You can t remove something from an empty object (like a bank account with no money, a stack or queue with no items, an empty food carousel, etc.). You can t add something to a bounded collection that has already reached its capacity (like a buffer). You can t use a resource that isn t currently ready (printer with no paper, network if connection is down, file that s no open for reading yet).

5 Handing what might be a temporary fault In a typical single-threaded program, if you reach a fault condition, the method that encounters it will typically end up doing one of the following: Ignore it and move on. Throw a language-supported exception so that another part of your program can handle it. Return an error code rather than a success code. public class BNC{ //BoundedNormalCounter private final int minvalue; private final int maxvalue; private int currentvalue; private BNC(min, int max, int initial) { minvalue = min; maxvalue = Math.max(min, max); currentvalue = Math.max(initial, min); public static BNC getinstance(int min, int max, int init) { return new BoundedNormalCounter(min, max, init); public int get() { return currentvalue; public boolean set(int newval) { if ((newval<minvalue) (newval>maxvalue)) return false; currentvalue = newval; return true; public boolean increment() { if (currentvalue==maxvalue) return false; currentvalue++; return true; public boolean decrement() { if (currentvalue==minvalue) return false; currentvalue--; return true;

6 private static void helperone(boundednormalcounter countin) { //Ignore it and move on. for (int i=0; i<add_this_many; i++) { countin.increment(); private static void helpertwo(boundednormalcounter countin) throws LimitExceededException { //Throw an exception. for (int i=0; i<add_this_many; i++) { if (!countin.increment()) throw new LimitExceededException("Tried to go to high."); private static boolean helperthree(boundednormalcounter countin) { //Return a failure code. for (int i=0; i<add_this_many; i++) { if (!countin.increment()) return false; return true; Handing what might be a temporary fault In a typical single-threaded program, if you reach a fault condition, the method that encounters it will typically end up doing one of the following: Ignore it and move on. Throw a language-supported exception so that another part of your program can handle it. Return an error code rather than a success code. What about multi-threaded programs where the issue might be resolved by another thread? Hopeful retries sleep/retry spin cycle.

7 private static int aggressiveadd(boundednormalcounter countin) { int succeeded = 0; for (int i=0; i<add_this_many; i++) { counterlock.lock(); while (!countin.increment()) { try { //if we omit this sleep then our busy-wait would become a livelock counterlock.unlock(); Thread.sleep(1); counterlock.lock(); catch (InterruptedException e) { e.printstacktrace(); succeeded++; counterlock.unlock(); return succeeded; private static int aggressivesubtract(boundednormalcounter countin) { int succeeded = 0; for (int i=0; i<subtract_this_many; i++) { counterlock.lock(); while (!countin.decrement()) { try { //if we omit this sleep then our busy-wait would become a livelock counterlock.unlock(); Thread.sleep(1); counterlock.lock(); catch (InterruptedException e) { e.printstacktrace(); succeeded++; counterlock.unlock(); return succeeded; Manual locking and unlocking In general, since locking mechanism where you manually lock and unlock won t release the lock automatically, you ll want to use a model such as: yourmanuallock.lock(); try { //Do the protected work. catch (Exception e) { //Deal with cleanup. finally { yourmanuallock.unlock();

8 Handing what might be a temporary fault In a typical single-threaded program, if you reach a fault condition, the method that encounters it will typically end up doing one of the following: Ignore it and move on. Throw a language-supported exception so that another part of your program can handle it. Return an error code rather than a success code. What about multi-threaded programs where the issue might be resolved by another thread? Hopeful retries sleep/retry spin cycle. Guarded suspension wait/reacquire (hopefully minimal spin). private static int aggressiveadd(boundednormalcounter countin) { int succeeded = 0; for (int i=0; i<add_this_many; i++) { synchronized(countin) { while (!countin.increment()) { try { countin.wait(); catch (InterruptedException e) { e.printstacktrace(); succeeded++; countin.notify(); return succeeded; private static int aggressivesubtract(boundednormalcounter countin) { int succeeded = 0; for (int i=0; i<subtract_this_many; i++) { synchronized(countin) { while (!countin.decrement()) { try { countin.wait(); catch (InterruptedException e) { e.printstacktrace(); succeeded++; countin.notify(); return succeeded;

9 Mix the ideas We could replace counterlock.unlock(); Thread.sleep(1); counterlock.lock(); with counterlock.wait(1); to be able to benefit from quicker releases from other threads and also take advantage of any Java-level efficiencies, but we d need to use an intrinsic lock (so we could just make the counterlock a reference to an Object). Handing what might be a temporary fault In a typical single-threaded program, if you reach a fault condition, the method that encounters it will typically end up doing one of the following: Ignore it and move on. Throw a language-supported exception so that another part of your program can handle it. Return an error code rather than a success code. What about multi-threaded programs where the issue might be resolved by another thread? Hopeful retries. Guarded suspension wait/reacquire (hopefully minimal spin). Optimistic retries.

10 Optimistic Retries As we ve seen, the process of locking and unlocking can be an expensive thing. If we generally expect there to not be contention on a resource, and if that resource is small in some way, it might make sense to do the following when you are ready to perform your operation that will alter the shared object, try the following until you succeed: Make a copy of the object. (this could be costly) Perform the operation on the copy. Call a synchronized commit method (sending it your old a new versions of the shared item) that will then check to see whether the object you altered is still the current object, and commit the change if so / offer to yield if not. For our example we will create a new class that will handle threadsafety itself called BoundedSafeOptimisticCounter as well as a less aggressive driver program. BoundedSafeOptimisticCounter (I) The get() method and a new commit(old, new) method will be synchronized. public synchronized int get() { return currentvalue; public synchronized boolean commit(int oldstatevalue, int newstatevalue) { if (currentvalue!= oldstatevalue) { return false; currentvalue = newstatevalue; return true;

11 BoundedSafeOptimisticCounter (II) The set(val) method and increment() and decrement() methods will not be synchronized. public boolean set(int newval) { if ((newval<minvalue) (newval>maxvalue) ) return false; while (true) { int localstatecopy = currentvalue; if (commit(localstatecopy, newval)) return true; Thread.yield(); public boolean increment() { while (true) { int localstatecopy = currentvalue; if (localstatecopy==maxvalue) return false; if (commit(localstatecopy, localstatecopy+1)) return true; Thread.yield(); Less aggressive workers private static int lessaggressiveadd(boundedsafeoptimisticcounter countin) { int succeeded = 0; for (int i=0; i<add_this_many; i++) { while (!countin.increment()) { succeeded++; try{thread.sleep(1); catch(interruptedexception e) { return succeeded;

12 Nested Monitors Issues If we use our instance confinement trick on a thread-safe object that uses wait/notify techniques, we could have a problem! Imagine a bounded safe counter that was written to use the wait/notifyall model internally. public class BSC_NotAtNoon{ //We don t allow increments at noon! private final BSC confinedcounter; private synchronized BSC_NotAtNoon(min, int max, int initial) { confinedcounter = BSC.getInstance(min, max, init); public synchronized int get() { return confinedcounter.get(); public boolean set(int newval) { return confinedcounter.set(newval); public synchronized boolean increment() { if (!currentlynoon()) { return confinedcounter.increment(); else return false; public synchronized boolean decrement() { return confinedcounter.decrement(); What happens if a BSC_NotAtNoon object s increment is called at 1:00pm but the counter is at its limit? Nested Monitors Lockout! When the BSC_NotAtNoon object s increment is called at 1:00pm and the counter is at its limit: the thread will wait and releases the lock on the inner BSC object however, even though it is in a wait set for the BSC object, it does not release its lock on the BSC_NotAtNoon object no other thread can have this BSC_NotAtNoon object s decrement called, so this thread will be waiting forever! Could try to solve this by not having the outer class synchronize, but then we are back at the problem of invariants across multiple composed objects