Learning from Bad Examples. CSCI 5828: Foundations of Software Engineering Lecture 25 11/18/2014

Similar documents
Thread Safety. Review. Today o Confinement o Threadsafe datatypes Required reading. Concurrency Wrapper Collections

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

Introduction to Concurrent Software Systems. CSCI 5828: Foundations of Software Engineering Lecture 08 09/17/2015

Introduction to Concurrent Software Systems. CSCI 5828: Foundations of Software Engineering Lecture 12 09/29/2016

Favoring Isolated Mutability The Actor Model of Concurrency. CSCI 5828: Foundations of Software Engineering Lecture 24 04/11/2012

G Programming Languages Spring 2010 Lecture 13. Robert Grimm, New York University

Introduction to Locks. Intrinsic Locks

Multithreaded Programming Part II. CSE 219 Stony Brook University, Department of Computer Science

The New Java Technology Memory Model

Grand Central Dispatch and NSOperation. CSCI 5828: Foundations of Software Engineering Lecture 28 12/03/2015

Threads and Locks. CSCI 5828: Foundations of Software Engineering Lecture 09 09/22/2015

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

Executive Summary. It is important for a Java Programmer to understand the power and limitations of concurrent programming in Java using threads.

Introducing Shared-Memory Concurrency

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

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

Design Approaches for Concurrent Systems. CSCI 5828: Foundations of Software Engineering Lecture 08 02/09/2012

CSE 451: Operating Systems Winter Lecture 7 Synchronization. Steve Gribble. Synchronization. Threads cooperate in multithreaded programs

Page 1. Challenges" Concurrency" CS162 Operating Systems and Systems Programming Lecture 4. Synchronization, Atomic operations, Locks"

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

Threads Questions Important Questions

+ Today. Lecture 26: Concurrency 3/31/14. n Reading. n Objectives. n Announcements. n P&C Section 7. n Race conditions.

Java Threads and intrinsic locks

CMSC 433 Section 0101 Fall 2012 Midterm Exam #1

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

PROCESS SYNCHRONIZATION

Synchronising Threads

G52CON: Concepts of Concurrency

SSC - Concurrency and Multi-threading Java multithreading programming - Synchronisation (II)

10/17/ Gribble, Lazowska, Levy, Zahorjan 2. 10/17/ Gribble, Lazowska, Levy, Zahorjan 4

CPS221 Lecture: Threads

CSE 451: Operating Systems Winter Lecture 7 Synchronization. Hank Levy 412 Sieg Hall

Operating Systems. Synchronization

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

Concurrency & Parallelism. Threads, Concurrency, and Parallelism. Multicore Processors 11/7/17

Synchronization. CS61, Lecture 18. Prof. Stephen Chong November 3, 2011

Safety SPL/2010 SPL/20 1

CSE332: Data Abstractions Lecture 23: Programming with Locks and Critical Sections. Tyler Robison Summer 2010

Dealing with Bugs. Kenneth M. Anderson University of Colorado, Boulder CSCI 5828 Lecture 27 04/21/2009

Lecture 16: Thread Safety in Java

CMSC 330: Organization of Programming Languages

COMP 213. Advanced Object-oriented Programming. Lecture 23. Shared Variables and Synchronization

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

Recap: Thread. What is it? What does it need (thread private)? What for? How to implement? Independent flow of control. Stack

Threads, Concurrency, and Parallelism

CMSC 433 Spring 2013 Exam 1

Lecture 03: Thread API (continue)

CSE 374 Programming Concepts & Tools

Dealing with Issues for Interprocess Communication

Locks. Dongkun Shin, SKKU

Static Methods. Why use methods?

Concurrency. Glossary

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

This is a talk given by me to the Northwest C++ Users Group on May 19, 2010.

Advanced Threads & Monitor-Style Programming 1/24

Lecture 13 Condition Variables

Concurrent Programming Lecture 10

Threads and Java Memory Model

Concurrency, Thread. Dongkun Shin, SKKU

COMP31212: Concurrency A Review of Java Concurrency. Giles Reger

RACE CONDITIONS AND SYNCHRONIZATION

CS11 Java. Fall Lecture 7

Java Concurrency in practice Chapter 9 GUI Applications

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

Concurrent Programming in C++ Venkat

INF 212 ANALYSIS OF PROG. LANGS CONCURRENCY. Instructors: Crista Lopes Copyright Instructors.

CSCD 330 Network Programming

Interprocess Communication By: Kaushik Vaghani

Agenda. Highlight issues with multi threaded programming Introduce thread synchronization primitives Introduce thread safe collections

G52CON: Concepts of Concurrency

Background. The Critical-Section Problem Synchronisation Hardware Inefficient Spinning Semaphores Semaphore Examples Scheduling.

Lecture 17: Sharing Objects in Java

CSCI-1200 Data Structures Fall 2009 Lecture 25 Concurrency & Asynchronous Computing

CS 2112 Lecture 20 Synchronization 5 April 2012 Lecturer: Andrew Myers

Synchronization SPL/2010 SPL/20 1

11/19/2013. Imperative programs

Safety and liveness for critical sections

Introduction to Asynchronous Programming Fall 2014

CS 31: Introduction to Computer Systems : Threads & Synchronization April 16-18, 2019

The Dining Philosophers Problem CMSC 330: Organization of Programming Languages

Hazard Pointers. Number of threads unbounded time to check hazard pointers also unbounded! difficult dynamic bookkeeping! thread B - hp1 - hp2

Advanced concurrent programming in Java Shared objects

Background. Old Producer Process Code. Improving the Bounded Buffer. Old Consumer Process Code

A Sophomoric Introduction to Shared-Memory Parallelism and Concurrency Lecture 5 Programming with Locks and Critical Sections

Only one thread can own a specific monitor

More thread safety and Concurrent collections. Nasser Giacaman CompSci 230: Software Design and Construction

Patterns Continued and Concluded. July 26, 2017

MULTITHREADING AND SYNCHRONIZATION. CS124 Operating Systems Fall , Lecture 10

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

Programmazione di sistemi multicore

Problems with Concurrency. February 19, 2014

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

Threads Tuesday, September 28, :37 AM

CS 241 Honors Concurrent Data Structures

Java Memory Model. Jian Cao. Department of Electrical and Computer Engineering Rice University. Sep 22, 2016

Data Races and Locks

Enums. In this article from my free Java 8 course, I will talk about the enum. Enums are constant values that can never be changed.

UNIT V CONCURRENT PROGRAMMING

The University of Texas at Arlington

Today: Synchronization. Recap: Synchronization

Transcription:

Learning from Bad Examples CSCI 5828: Foundations of Software Engineering Lecture 25 11/18/2014 1

Goals Demonstrate techniques to design for shared mutability Build on an example where multiple threads access an EnergySource to demonstrate the problems that occur with bad design we will refactor the program until we ve tamed shared mutability and have thread safe code 2

Shared Mutability We ve been talking at an abstract level about the dangers of shared mutability When we use the word danger, we mean that the code has the potential to be unstable there may be deadlocks hiding in the code there may be race conditions, so the values of variables may behave unpredictability And, the danger is that you can spend a lot of time trying to debug these conditions If you work with concurrent code that uses shared mutability, then you need to be able to identify the types of code structures that can lead to problems and learn how to eliminate them 3

Controlling your variables (I) In a shared mutability design, you need to have a clear sense of which threads can access which variables You can then design into the program the ways in which these variables can be protected using the synchronization constructs discussed in previous lectures In particular, avoiding the use of the keyword synchronized and, instead, making use of the Lock interface from java.util.concurrent for fine-grained access control Note: this example is written in Java but its lessons are more general and will apply to other languages that provide access to low-level thread primitives 4

Controlling your variables (II) If you have ensured that all mutable variables are either accessed by only one thread or accessed by multiple threads using Lock to coordinate updates then you can be confident that your program will be free from thread-related dangers; If, however, a thread can access one of these variables without passing through the protections you put in place then the variable is said to have escaped and you are open to race conditions and non-stable code 5

Controlling your variables (III) A complex aspect to this analysis is the different ways in which values can escape Imagine we have Class A that creates an instance of a collection class and Class A ensures that the collection is accessed in a thread safe way the instance variable is private all methods that update the collection make use of the Lock interface 6

Controlling your variables (IV) All of these protections are null and void if one of Class A s methods returns a pointer to the collection public List getrecords() { return records; } At this point, Class A cannot protect this collection Any class that calls this method can then directly update the collection without using Class A For instance, Class B might call getrecords() and make its pointer to Class A s collection class visible to other threads At this point the records variable has escaped and is no longer protected 7

Controlling your variables (V) The same is true if Class A decides to pass records to some other method as input {... ; records = foo.update(records);... } If the object foo decides to keep a pointer to all of the collections passed to its update() method, then records has escaped and all of Class A s protections are, again, useless Finally, if a class has public instance variables or public static variables then any of these variables can easily escape Code can simply reach in and update the instances without the host class knowing about it 8

Controlling your variables (VI) By now it should be clear that visibility specifications public, protected, private have nothing to do with protecting a variable from access by multiple threads The values pointed at by private variables can be passed to other classes who can then point at those values stripping them of their protection If you have a very small program, then you should be able to conduct the analysis of whether a variable has escaped its protection or not but as your programs get larger, it becomes more and more difficult to keep track of all the ways a variable is accessed and this is what causes the pain of debugging shared mutability designs 9

Example: Step 1 To demonstrate these issues, let s look at a bad example of shared mutability design EnergySource is a resource that maintains a certain amount of energy Clients can make use of this energy by calling useenergy() and specifying how much energy they need Internally, EnergySource starts a thread that will slowly replenish the EnergySource if its energy level ever falls below the maximum I have augmented this example with client code that makes use of the EnergySource a monitor that prints out the current level of the source on a periodic basis and consumers who read the current level and then consume a random amount of energy DEMO 10

Discussion As the book discusses, the EnergySource class is a HORRIBLE instance of concurrent design it does pretty much everything wrong the internal thread is started incorrectly the internal thread can access the source before it has been initialized its internal instance variable is mutable and unprotected (race condition) the internal thread loops forever until a boolean flag changes state changing the boolean flag may not cross the memory barrier thread is stuck endlessly looping and sleeping, consuming resources one internal thread is created per instance; threads are expensive! 11

Step 2: Fix creation of internal thread (I) We do not want to create threads in our constructor If we call start() on those threads in the constructor they may start accessing our object before it exits the constructor! as a result, they will be accessing the object in an inconsistent state We want the call to the constructor to complete before any other object accesses the energy source This allows us to make sure the energy source is in a consistent state then, we can design the class such that each method starts in a consistent state, performs its service, and ensures that it is leaving the object in a consistent state before it returns 12

Step 2: Fix creation of internal thread (II) To address this problem, we make use of a factory pattern The constructor of the class is made private This prevents other classes from creating instances of EnergySource A private instance method (init) is created to create the internal thread A static method is created to allow classes to acquire an instance of EnergySource the static factory method creates an instance of the class (constructor will fully initialize class) calls the init method to start the thread returns the instance to the caller DEMO 13

Step 3: Get rid of internal thread The internal thread was created so that periodically the EnergySource would be replenished The original author probably felt that a thread was the only way to accomplish this Java has a class called Timer that can be used to fire events on a periodic basis but creating one Timer per instance of EnergySource is wasteful Instead, we ll use a ScheduledThreadPoolExecutor DEMO It can allocate a certain number of threads and then reuse them to handle the task of replenishing multiple energy sources The thread pool will be static, so it will be shared across all instances 14

Discussion (I) As a result of adding an instance of ScheduledExecutorService to EnergySource the private init() method is changed such that instead of creating a thread it now creates an instance of a task that it submits to the thread pool the task simply calls replenish we ask that the task be run every second the replenish method is now simplified: check level, increment if needed no more loop, no more sleeping the boolean flag goes away the request to stop the energy source, now just cancels the task 15

Discussion (II) One complication With the addition of a static thread pool, we need to come up with a way to shut the thread pool down We have two options Add a static shutdown() method to EnergySource Call this method when its time to shut our program down Configure the pool with a thread factory that sets all threads to be daemon threads I chose the former; it s simpler (at least for this example program) 16

Step 4: Ensure visibility Our shared mutable instance variable (level) is not protected changes to it may not pass the memory barrier race conditions exist since multiple threads may try to read the value of level at the same time and then try to consume energy based on that value Our Consumer thread has a transaction problem in this regard that we ll fix later We ll start by fixing this problem by adding the synchronized keyword to all methods that access the shared instance variable This protects the variable but greatly reduces performance If we have a lot of threads accessing EnergySource, most of them will be blocked while one thread is inside one of these methods 17

Step 5: Enhance Concurrency Use of the synchronized keyword is too restrictive in terms of performance We ll change our instance variable from a long to an AtomicLong We can then get rid of our synchronized keyword and allow the threads to access the energy source as fast as possible The AtomicLong will ensure that the minimum amount of synchronization is used to protect its value from multiple threads Note: use of AtomicLong.compareAndSet(expected, new) in useenergy() a thread says here is the value that I think is current; if it is current, then change it to this new value Protects against situations where a thread reads a value and it gets updated before it can write a new value; the update fails, if it gets expected wrong 18

We still need a transaction Even with these protections, our consumers still get into problems Consumer 0 tries to consume 23: SUCCESS! Consumer 2 tries to consume 94: FAIL! Consumer 1 tries to consume 89: FAIL! Even though Consumer 0 had updated the EnergySource Consumer 1 and Consumer 2 both read the level of EnergySource at the same time and tried to consume an invalid amount of energy We now need to address this problem with our consumers 19

Step 6: Add a notion of transaction to consumer Our consumers are designed to read the value of the energy source use that value to generate a random amount of energy to consume and then consume that amount of energy The problem? they do not do this read/update in a transaction as a result, they can all read the same amount at the same time and then all move on to consume different amounts, some of which will be invalid All of the work we ve done in EnergySource does not solve this problem We ll solve it via a shared lock; if we had more than one type of thread, we d have to place this lock in EnergySource; for now, we will create it in Consumer 20

Step 7: Fix the problem with replenish We do have a problem even with the transaction, it s possible that the replenish task slips in between a Consumer s read and write, incrementing the value, and causing the Consumer s write to fail This would manifest in the step06 program like this Consumer 7 tries to consume 2: FAIL! It s very hard to make this happen, but it s possible So, we need to share the lock between the consumers and the replenish task We add a public lock to EnergySource and update Consumers to use that lock instead (deleting the lock inside of Consumer) and updating replenish() to use that lock as well 21

Step 8: Update semantics of replenish The way the program is written currently, we consume the energy of the EnergySource very quickly Let s allow replenish to do more than increment the level It can do this safely since all consumers will be blocked during its update Let s change the consumers to be more modest in their consumption We should now have a program in which the EnergySource stays at a reasonable level, rather than stuck down at one or two units constantly 22

Step 9: Ensure Atomicity The last change that the book makes is to add another mutable variable to EnergySource This variable will track the number of times that the EnergySource is used The purpose of this change is to show that AtomicLong is insufficient to keep changes to two separate variables coordinated Instead, we need a lock to ensure that both variables are updated in tandem We ll change our Lock to a ReadWriteLock, get rid of the AtomicLong, and update Consumer, Monitor, and the replenish task to make use of the new ReadWriteLock Everything works fine and we get the maximum amount of concurrency that can occur, given our need to protect the two variables 23

Summary Learned useful lessons about taming shared mutability Do not create threads in constructors; create in static factory methods Do not create arbitrary threads (replenish thread); use thread pools Ensure access to mutable variables cross memory barrier Evaluate the granularity of locks to promote concurrency avoid synchronized if at all possible Ensure atomicity of multiple mutable variables via locks Note: the final program is thread safe and as performant as we can make it unfortunately, the code is quite complex; an unavoidable aspect of the shared mutability approach to the design of concurrent software systems 24

Coming Up Next Lecture 26: The Design of Design Lecture 27: Return to our Concurrency Textbook 25