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

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

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

Models of concurrency & synchronization algorithms

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

The New Java Technology Memory Model

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

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

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

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

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

Concurrent Programming

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

Chapter 32 Multithreading and Parallel Programming

Multiple Inheritance. Computer object can be viewed as

Synchronization in Java

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

What is a thread anyway?

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

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

G52CON: Concepts of Concurrency

Programmazione Avanzata e Paradigmi Ingegneria e Scienze Informatiche - UNIBO a.a 2013/2014 Lecturer: Alessandro Ricci

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

Lecture 29: Java s synchronized statement

Concurrent Programming using Threads

Synchronization in Concurrent Programming. Amit Gupta

Dealing with Issues for Interprocess Communication

Threads and Parallelism in Java

Pre- and post- CS protocols. CS 361 Concurrent programming Drexel University Fall 2004 Lecture 7. Other requirements for a mutual exclusion algorithm

CS533 Concepts of Operating Systems. Jonathan Walpole

CMSC 330: Organization of Programming Languages

Advances in Programming Languages

Operating Systems CMPSCI 377 Spring Mark Corner University of Massachusetts Amherst

Lecture 21: Transactional Memory. Topics: consistency model recap, introduction to transactional memory

Problems with Concurrency. February 19, 2014

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

The Dining Philosophers Problem CMSC 330: Organization of Programming Languages

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

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

Synchronization COMPSCI 386

Today: Synchronization. Recap: Synchronization

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

CS 351 Design of Large Programs Threads and Concurrency

What is the Race Condition? And what is its solution? What is a critical section? And what is the critical section problem?

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

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

OS06: Monitors in Java

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

Performance Throughput Utilization of system resources

Java Threads. Introduction to Java Threads

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

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

Reminder from last time

CST242 Concurrency Page 1

Lecture 5: Synchronization w/locks

CSL373: Lecture 5 Deadlocks (no process runnable) + Scheduling (> 1 process runnable)

7. MULTITHREDED PROGRAMMING

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

CS11 Java. Fall Lecture 7

Threads and Java Memory Model

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

Implementing Coroutines. Faking Coroutines in Java

Multi-threading in Java. Jeff HUANG

Potential violations of Serializability: Example 1

JAVA and J2EE UNIT - 4 Multithreaded Programming And Event Handling

Multitasking Multitasking allows several activities to occur concurrently on the computer. A distinction is usually made between: Process-based multit

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

Advanced Concepts of Programming

Monitors; Software Transactional Memory

Synchronization. Silvina Hanono Wachman Computer Science & Artificial Intelligence Lab M.I.T.

IT 540 Operating Systems ECE519 Advanced Operating Systems

CMSC 330: Organization of Programming Languages

1 of 6 Lecture 7: March 4. CISC 879 Software Support for Multicore Architectures Spring Lecture 7: March 4, 2008

Programmazione di sistemi multicore

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

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

THREADS AND CONCURRENCY

Threads Questions Important Questions

Concurrent Programming Lecture 10

Distributed Systems COMP 212. Revision 2 Othon Michail

Concurrency - Topics. Introduction Introduction to Subprogram-Level Concurrency Semaphores Monitors Message Passing Java Threads

CSCD 330 Network Programming

Concurrent & Distributed Systems Supervision Exercises

Resource management. Real-Time Systems. Resource management. Resource management

RACE CONDITIONS AND SYNCHRONIZATION

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

Handouts. 1 Handout for today! Recap. Homework #2 feedback. Last Time. What did you think? HW3a: ThreadBank. Today. Small assignment.

Operating Systems. Synchronization

Lecture: Consistency Models, TM. Topics: consistency models, TM intro (Section 5.6)

Note: in this document we use process and thread interchangeably.

Intro to Transactions

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

JAVA CONCURRENCY FRAMEWORK. Kaushik Kanetkar

COMP31212: Concurrency A Review of Java Concurrency. Giles Reger

Principles of Software Construction: Concurrency, Part 2

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

! Why is synchronization needed? ! Synchronization Language/Definitions: ! How are locks implemented? Maria Hybinette, UGA

Synchronization SPL/2010 SPL/20 1

A Sophomoric Introduction to Shared-Memory Parallelism and Concurrency Lecture 4 Shared-Memory Concurrency & Mutual Exclusion

Real-Time and Concurrent Programming Lecture 4 (F4): Monitors: synchronized, wait and notify

Transcription:

G22.2110-001 Programming Languages Spring 2010 Lecture 13 Robert Grimm, New York University 1

Review Last week Exceptions 2

Outline Concurrency Discussion of Final Sources for today s lecture: PLP, 12 Barrett. Lecture notes, Fall 2008. Lecture notes for CMU s 15-440, Fall 2009: http://www.andrew.cmu.edu/course/15-440-sp09/ 3

Concurrency So far, we have focused on sequential programs. But many programs are, in fact, concurrent and consist of more than one active execution context. We call such an execution context a thread. Reasons for concurrency: Reflection of logical structure of problem: many programs must keep track of more than one independent task at the same time To interact with multiple independent physical devices To increase performance Note that we want concurrency even with a single processor core, e.g., to capture application domain, to overlap computation with I/O, to support multi-tasking, and so on. We absolutely must have it for multiand many-core processors, which likely will be the most important source of performance increases for the forseeable future. 4

Granularity of Concurrency At the instruction level: Explicit through SIMD instructions, which a apply a Single Instruction on Multiple Data. Implicit in superscalar core, which has duplicated execution units (e.g., several integer arithmetic units) and thus can perform several operations at the same time. At the program level: Explicit with threads that coordinate through shared memory (ADA, JAVA, C#). Explicit with threads that are isolated from each other and coordinate through message passing (ERLANG). Implicit through SIMD-like programming languages like APL. Many older languages such as C, C++, or FORTRAN do not have built-in support for concurrency at all, but instead rely on libraries. 5

Creating Threads in JAVA Implement Runnable: public class Worker implements Runnable { public void run() { // Do the real work here. public void pulltrigger() { (new Thread(new Worker())).start(); The constructor invocation creates the new thread and the invocation of start begins its execution. The implementation of Thread.start internally calls the Runnable s run method. 6

Creating Threads in JAVA (ii) Extend Thread: public class Worker extends Thread { public void run() { // Do the real work here. public void pulltrigger() { (new Worker()).start(); The constructor invocation creates the new thread and the invocation of start begins its execution. The implementation of Thread.start internally calls the overridden run method. 7

Creating Threads in JAVA (iii) Creating threads on demand takes time (and memory) and is wasteful if an repeatedly application creates and terminates threads (think servers). A better solution is to pre-allocate some number of threads and parcel out tasks to threads that are currently not busy. This service is provided by a thread pool. Before JAVA 1.5, developers had to write their own thread pool implementations, which can be rather tricky (believe me, I have done that). As of JAVA 1.5, support for so-called executors is provided in the java.util.concurrent package. 8

More Ways to Create Threads Languages and libraries provide a variety of different ways to create new threads Co-Begin: A list of program blocks that are allowed to run in parallel Parallel Loops: Loops in which multiple iterations are allowed to run at the same time Launch at Elaboration: Threads declared with syntax similar to subroutines. Automatically created when the program runs. Fork: General mechanism to create a new thread Join: Wait until a thread created with fork is finished Implicit receipt: New thread created automatically in response to a request (on a server, for example) Early Reply: Like a procedure call, except subroutine executes reply instead of return at which point both the caller and callee continue in parallel 9

Threads and Time Each thread virtualizes a processor core. When the thread is actively executing, it is progressing in wall-clock time. When it is not executing, it has no way of observing that it is asleep after all, it is not executing. A thread can voluntarily give up its processor core: // Get the current thread. Thread t = Thread.currentThread(); // Give up. t.yield(); A little more conservatively, a thread can give up its core for a limited time: Thread t = Thread.currentThread(); // Bite the apple. try { t.sleep(1000); // One second. catch (InterruptedException x) { // Hello Prince. 10

Race Conditions public class Account { private long balance; public void withdraw(long amount) throws Overdraft { if (amount > balance) throw new Overdraft(); balance -= amount;... Let s start with a balance of $1,000 in account checking and two threads A and B. What could possibly go wrong? 11

Race Conditions (ii) 1 public class Account { 2 private long balance; 3 public void withdraw(long amount) throws Overdraft { 4 if (amount > balance) throw new Overdraft(); 5 balance -= amount; 6 7... 8 Let s start with a balance of $1,000 in account checking and two threads A and B. What could possibly go wrong? A: call checking.withdraw(800) B: call checking.withdraw(800) A: pass balance check in line 4 B: pass balance check in line 4 A: update balance in line 5 B: update balance in line 5 The remaining balance is $(600). Oops. 12

Race Conditions (iii) 1 public class Account { 2 private long balance; 3 public void withdraw(long amount) throws Overdraft { 4 if (amount > balance) throw new Overdraft(); 5 balance -= amount; 6 7... 8 Let s start with a balance of $1,000 in account checking and two threads A and B. What could possibly go wrong? Even more insidiously, the statement on line 5 really is one memory read to get value of balance, one subtraction to compute the difference, and one memory write to update the value of balance. Consequently, the following thread interleaving is possible: A: read balance B: read balance A: compute and write new balance B: compute and write new balance Thread A s withdrawal succeeded but is not reflected in the account s state at all. Double oops. 13

Memory Consistency Model Modern processors have several levels of caches. Furthermore, some caches may be per-core and some caches may be shared across cores on a processor, but never across different processors. Ensuring that all processor cores see the same memory contents at all times requires consistency traffic between caches and memory. The illusion of perfect order is called sequential consistency. I.e., all writes become visible to all cores in the same order and all of a core s writes become visible in the performed order. Sequential consistency is intuitive but expensive to maintain. Consequently, most modern architectures feature more relaxed consistency models and require explicit synchronization instructions to enforce ordering. As a result, memory races can be very very tricky and may even differ across architectures. 14

Monitors A monitor is an object that ensures mutual exclusion for its methods, i.e., only one thread can execute a method at a given time. In Java, every object has an implicit monitor. To guarantee mutual exclusion, you simply annotate a method with the synchronized modifier: public class Account { private long balance; public synchronized void withdraw(long amount) throws Overdraft { if (amount > balance) throw new Overdraft(); balance -= amount;... Now every withdrawal is guaranteed to execute atomically, as one indivisible unit. 15

Synchronized Blocks To provide more flexibility in using monitors, Java also supports synchronized blocks, which explicitly specify the monitor object: synchronized (monitor) {... Again, every object implicitly has a monitor and thus can be used to ensure mutual exclusion in a synchronized block. Integrating support for synchronized methods and blocks into the language is a Good Thing TM. Both can be implemented with a lock, which is acquired before entering the method or block and which is released when exiting the method or block. By only supporting synchronized methods and blocks, the implementation can automatically ensure that all lock acquire and release operations are always well-matched even when exiting the method or block through an exception. 16

The Trouble with JAVA Monitors A monitor object always uses itself to synchronize methods. A synchronized block, however, can use any JAVA object, including an object that has synchronized methods. Consequently, an ill-behaved program can synchronize on a monitor and then loop forever, thus preventing the monitor from ever executing synchronized methods again. The problem is a lack of encapsulation for JAVA monitors. Instead of using synchronized methods, it is cleaner to use an explicit and private lock object: public class Monitor { private Object lock = new Object(); public void examplemethod(...) { synchronized (lock) {...... 17

Lock Everything? So, if race conditions are such a danger for concurrent programs, why not protected all data and operations with locks, locks, and more locks? Locks can be rather expensive, since each synchronized method or block must acquire the underlying lock before executing any code and then release that lock again before exiting from the method or block (and do that even when exiting through an exception). Locks easily lead to deadlock... 18

Deadlock public void m1() { synchronized (l1) {... synchronized (l2) {... public void m2() { synchronized (l2) {... synchronized (l1) {... Conside two threads A and B. Thread A calls m1() and thread B calls m2(). What could possibly go wrong? 19

Deadlock (ii) 1 public void m1() { 2 synchronized (l1) {... 3 synchronized (l2) { 4... 5 6 7 8 public void m2() { 9 synchronized (l2) {... 10 synchronized (l1) { 11... 12 13 14 Conside two threads A and B. Thread A calls m1() and thread B calls m2(). What could possibly go wrong? I m glad you asked: A:1, A:2, B:8, B:9, and then? 20

Avoiding Deadlock Some options: Follow well-established algorithms and heuristics, such as using only one lock at a time or always acquiring locks in the same order. Switch to transactional memory, which replaces explicit locks with atomic blocks. All code in an atomic block either commits, i.e., executes as one indivisible operation, or aborts, i.e., appears not to have But: executed at all. These semantics support arbitrary nesting of atomic blocks, thus eliminating deadlock. Deadlock avoidance algorithms and heuristics can be hard to follow and may simply not apply at all. Transactional memory is not yet available in maintstream languages. Furthermore, transactional memory implementations need to be able to undo all operations of an atomic block, which is impossible for I/O. 21

Condition Variables Sometimes, concurrent code needs to wait for a condition to become true. For example, a queue s take operation requires the queue to contain at least one element. One solution is to poll: repeatedly perform the condition s test in a loop. But polling means that a processor core is busy without doing much useful work. This is fine for short durations, but not such a great idea when polling takes a while. Furthermore, polling code must not hold any locks, making it harder to get right. A better solution are condition variables, which support three key operations: wait makes the current thread wait, optionally with a timeout. notify wakes up some already waiting thread. notifyall wakes up all waiting threads. Every condition variable has an associated lock, which must be held when invoking either of the three operations. Each condition variable operation, in turn, temporarily relinquishes the lock so that other threads can make progress. Each JAVA object not only has an implicit monitor but also an implicit condition variable. 22

Condition Variables in JAVA public class Queue<E> {... public E take() { synchronized (cond) { while (isempty()) { try { cond.wait(); catch (InterruptedException e) {... // Remove element from internal storage. public void give(e e) { synchronized (cond) {... // Add e to internal storage. cond.notify(); Note that condition variables really are library support for concurrency, at least in JAVA. 23

JAVA Concurrency in One Slide Three simple facts of concurrent life: Every object is a monitor and supports synchronized methods Every object is a lock and supports synchronized blocks Every object also is a condition variable supporting wait, notify, and notifyall JAVA 1.5 adds many more options through the java.util.concurrent, java.util.concurrent.atomic, and java.util.concurrent.locks packages. Other design points are certainly possible; see, for example, Clark Barrett s slides from the Fall 2008 for (more than you ever wanted to know about) ADA. Also, programming with threads is inherently hard: race conditions, deadlock, livelock, priority inversion, and so on are a fact of concurrent life. 24

Implementing Threads A minimal threading implemententation needs per-thread storage for registers etc. This is typically called the thread control block. It also needs to know which thread is currently running and which threads are ready to run, i.e., the ready queue. Finally, each condition variable needs a queue of threads that are waiting on that condition. The scheduler then uses these data structures to save the old thread s state, to select which thread to run next, and to restore the new thread s state. But: We still need locks... 25

Hardware Support for Synchronization Implementing locks with memory read and write instructions is possible but complex and slow. More powerful atomic instructions help: int TAS(<location>) { if (*<location> == 0) { *<location> = 1; return 0; else { return 1; int CAS(<location>, <expected>, <updated>) { if (*<location> == <expected>) { *<location> = <updated>; return 0; else { return 1; Note that TAS(x) == CAS(x,0,1). 26

Implementing a Lock With CAS, implementing a lock becomes straight-forward: void acquire(<lock>) { while (CAS(<lock>, 1, 0)) ; void release(<lock>) { *<lock> = 1; Voilà, we have a spin lock. Note that we can avoid all this complexity if our threading implementation uses cooperative scheduling instead of preemption. Under the latter, a hardware interrupt periodically invokes the scheduler, hence we need to use atomic instructions. Under the former, each thread periodically calls into the scheduler. That simplifies matters (no possibility of interruption) but also complicates matters (developers need to write well-behaved code). 27