CMSC 330: Organization of Programming Languages Concurrency / Multiprocessing.

Slides:



Advertisements
Similar presentations
Chapter 6 Concurrency: Deadlock and Starvation Operating Systems: Internals and Design Principles, 6/E William Stallings Patricia Roy Manatee Community.
Advertisements

Operating Systems: Monitors 1 Monitors (C.A.R. Hoare) higher level construct than semaphores a package of grouped procedures, variables and data i.e. object.
Concurrency: Deadlock and Starvation Chapter 6. Deadlock Permanent blocking of a set of processes that either compete for system resources or communicate.
Chapter 6 Concurrency: Deadlock and Starvation Operating Systems: Internals and Design Principles, 6/E William Stallings Patricia Roy Manatee Community.
Chapter 6: Process Synchronization
Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition, Chapter 6: Process Synchronization.
CMSC 330: Organization of Programming Languages Threads Classic Concurrency Problems.
1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads.
Chapter 6 Concurrency: Deadlock and Starvation
Threading Part 2 CS221 – 4/22/09. Where We Left Off Simple Threads Program: – Start a worker thread from the Main thread – Worker thread prints messages.
Avishai Wool lecture Introduction to Systems Programming Lecture 4 Inter-Process / Inter-Thread Communication.
Review: Process Management Objective: –Enable fair multi-user, multiprocess computing on limited physical resources –Security and efficiency Process: running.
Concurrency: Deadlock and Starvation Chapter 6. Revision Describe three necessary conditions for deadlock Which condition is the result of the three necessary.
Concurrency: Mutual Exclusion, Synchronization, Deadlock, and Starvation in Representative Operating Systems.
Deadlock Prevention CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han.
1 Concurrency: Deadlock and Starvation Chapter 6.
Definitions Process – An executing program
CPS110: Implementing threads/locks on a uni-processor Landon Cox.
Race Conditions CS550 Operating Systems. Review So far, we have discussed Processes and Threads and talked about multithreading and MPI processes by example.
A. Frank - P. Weisberg Operating Systems Introduction to Cooperating Processes.
U NIVERSITY OF M ASSACHUSETTS, A MHERST Department of Computer Science Emery Berger University of Massachusetts, Amherst Operating Systems CMPSCI 377 Lecture.
Concurrency Recitation – 2/24 Nisarg Raval Slides by Prof. Landon Cox.
1 Concurrency: Deadlock and Starvation Chapter 6.
Parallel Processing (CS526) Spring 2012(Week 8).  Thread Status.  Synchronization in Shared Memory Programming(Java threads ) ◦ Locks ◦ Barriars.
A Bridge to Your First Computer Science Course Prof. H.E. Dunsmore Concurrent Programming Threads Synchronization.
Chapter 6 Concurrency: Deadlock and Starvation Operating Systems: Internals and Design Principles, 6/E William Stallings Dave Bremer Otago Polytechnic,
Object Oriented Analysis & Design SDL Threads. Contents 2  Processes  Thread Concepts  Creating threads  Critical sections  Synchronizing threads.
1 Processes, Threads, Race Conditions & Deadlocks Operating Systems Review.
Java Threads. What is a Thread? A thread can be loosely defined as a separate stream of execution that takes place simultaneously with and independently.
Copyright © 1997 – 2014 Curt Hill Concurrent Execution of Programs An Overview.
1 Announcements The fixing the bug part of Lab 4’s assignment 2 is now considered extra credit. Comments for the code should be on the parts you wrote.
COMP 111 Threads and concurrency Sept 28, Tufts University Computer Science2 Who is this guy? I am not Prof. Couch Obvious? Sam Guyer New assistant.
Operating Systems ECE344 Ashvin Goel ECE University of Toronto Mutual Exclusion.
4061 Session 21 (4/3). Today Thread Synchronization –Condition Variables –Monitors –Read-Write Locks.
Deadlocks Silberschatz Ch. 7 and Priority Inversion Problems.
CSC321 Concurrent Programming: §5 Monitors 1 Section 5 Monitors.
CS399 New Beginnings Jonathan Walpole. 2 Concurrent Programming & Synchronization Primitives.
Review for Quiz-2 Applied Operating System Concepts Chap.s 1,2,6,7 - ECE3055b, Spring 2005.
Copyright © Curt Hill Concurrent Execution An Overview for Database.
Debugging Threaded Applications By Andrew Binstock CMPS Parallel.
13-1 Chapter 13 Concurrency Topics Introduction Introduction to Subprogram-Level Concurrency Semaphores Monitors Message Passing Java Threads C# Threads.
CENG334 Introduction to Operating Systems Erol Sahin Dept of Computer Eng. Middle East Technical University Ankara, TURKEY URL:
CMSC 330: Organization of Programming Languages Threads.
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Computer Systems Principles Synchronization Emery Berger and Mark Corner University.
CS 241 Section Week #7 (10/22/09). Topics This Section  Midterm Statistics  MP5 Forward  Classical Synchronization Problems  Problems.
CS333 Intro to Operating Systems Jonathan Walpole.
Deadlocks Mark Stanovich Operating Systems COP 4610.
Deadlocks.  Deadlocks: Occurs when threads are waiting for resources with circular dependencies Often involve nonpreemptable resources, which cannot.
1 5-High-Performance Embedded Systems using Concurrent Process (cont.)
Silberschatz, Galvin and Gagne ©2013 Operating System Concepts – 9 th Edition Chapter 5: Process Synchronization.
Deadlocks Copyright ©: University of Illinois CS 241 Staff1.
1 Threads in Java Jingdi Wang. 2 Introduction A thread is a single sequence of execution within a program Multithreading involves multiple threads of.
Silberschatz, Galvin and Gagne ©2009 Edited by Khoury, 2015 Operating System Concepts – 9 th Edition, Chapter 7: Deadlocks.
Mutual Exclusion -- Addendum. Mutual Exclusion in Critical Sections.
NETW 3005 Monitors and Deadlocks. Reading For this lecture, you should have read Chapter 7. NETW3005 (Operating Systems) Lecture 06 - Deadlocks2.
Synchronization Deadlocks and prevention
Multithreading / Concurrency
Background on the need for Synchronization
Applied Operating System Concepts -
Multithreading.
Shared Memory Programming
Chapter 7: Synchronization Examples
Background and Motivation
Concurrency: Mutual Exclusion and Process Synchronization
Conditions for Deadlock
CS333 Intro to Operating Systems
Foundations and Definitions
CENG334 Introduction to Operating Systems
CSE 542: Operating Systems
CSE 542: Operating Systems
Presentation transcript:

CMSC 330: Organization of Programming Languages Concurrency / Multiprocessing

Multiprocessing Multiprocessing: The use of multiple parallel computations We have entered an era of multiple cores... –Hyperthreading –Dual-core and quad-core consumer processors –Symmetric Multi-Processing (SMP) machines …and multiple nodes –Computational clusters –Grid and cloud computing CMSC 3302

Technologies Multiple cores: –SIMD arithmetic and GPUs –Java and Ruby threads –POSIX threads –OpenMP Multiple nodes: –MPI –MapReduce CMSC 3303

Amdahl’s Law Informally: The theoretical maximum speedup using multiprocessing is limited by a program’s sequential performance. CMSC 3304 Sequential portion Parallel portion

CMSC 3305 Computation Abstractions CPU 1CPU 2 p3p1p2p4 t1 t2 t1 t2 t3 t1 t4 t5 A computer Processes Threads

CMSC 3306 Processes vs. Threads int x; foo() { …x… } int x; foo() { …x… } int x; foo() { …x… } foo() { …x… } Processes do not share data Threads share data within a process

CMSC 3307 So, What Is a Thread? Conceptually: it is a parallel computation occurring within a process Implementation view: it’s a program counter and a stack. The heap and static area are shared among all threads All processes have at least one thread (main) –Programs vs. processes

CMSC 3308 Thread Creation execution (time) main thread thread starts thread ends thread join

CMSC 3309 Implementation View Per-thread stack and instruction pointer –Saved in memory when thread suspended –Put in hardware esp/eip when thread resumes eip esp

CMSC Threads vs. Processes Threads –Less expensive to create –Shared memory paradigm –Easier to program –Limited scalability (tens of threads) Processes –More expensive to create (system call) –Message-passing paradigm –Harder to program –Highly scalable (thousands of processes)

CMSC Programming Threads Threads are available in most languages –C, C++, Objective Caml, Java, SmallTalk … In many languages (e.g., C and C++), threads are a platform specific add-on –Not part of the language specification They're part of the Java language specification Thread and Monitor modules in Ruby

Ruby Threads Create thread using Thread.new –New method takes code block argument t = Thread.new {...body of thread... } t = Thread.new (arg) { | arg |...body of thread... } –Join method waits for thread to complete t.join Example: myThread = Thread.new { sleep 1 # sleep for 1 second puts “New thread awake!" $stdout.flush # flush makes sure output is seen } CMSC 330

13 Thread Lifecycle While a thread executes, it goes through a number of different phases –New: created but not yet started –Runnable: can run on a free CPU –Running: currently executing on a CPU –Blocked: waiting for I/O or on a lock –Sleeping: paused for a user-specified interval –Terminated: completed

Thread Lifecycle CMSC 330 New Sleeping Runnable Running Terminated Blocked zzzzz...

CMSC Which Thread to Run Next? Look at all runnable threads –A good choice to run is one that just became unblocked because A lock was released (we’ll see this in a minute) I/O became available It finished sleeping, etc. Pick a thread and start running it –Higher-priority threads get preference –Handled by the system or VM scheduler

CMSC Scheduling CPU 1 CPU 2 p1 p2 p1 p2 One process per CPU p2 threads: p1 threads:

CMSC Scheduling CPU 1 CPU 2 p1 p2 p1 p2 Threads shared between CPUs p2 threads: p1 threads:

CMSC Concurrency and Shared Data Concurrency is easy if threads don’t interact –Each thread does its own thing, ignoring other threads –Typically, however, threads need to communicate with each other Communication is done by sharing data –Different threads may access the heap simultaneously –But the scheduler might interleave threads arbitrarily –Problems can occur if we’re not careful

Problem: Data Race Multiple processes may attempt to modify the same value at the same time, and their edits may conflict Concept: Atomicity –Atomic operations appear to happen instantaneously –Guaranteed to be isolated from other threads –Usually succeed or fail; no partial success CMSC 330

20 Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 0 Start: both threads ready to run. Each will increment the global cnt. Shared state

CMSC Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 0 T1 executes, grabbing the global counter value into its own y. Shared state y = 0

CMSC Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 1 T1 executes again, storing its value of y + 1 into the counter. Shared state y = 0

CMSC Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 1 T1 finishes. T2 executes, grabbing the global counter value into its own y. Shared state y = 0 y = 1

CMSC Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 2 T2 executes, storing its incremented cnt value into the global counter. Shared state y = 0 y = 1

CMSC But When it's Run Again? Suppose the second thread has a higher priority, and the first thread gets paused during execution

CMSC Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 0 Start: both threads ready to run. Each will increment the global count. Shared state

CMSC Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 0 T1 executes, grabbing the global counter value into its own y. Shared state y = 0

CMSC Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 0 T1 is preempted. T2 executes, grabbing the global counter value into its own y. Shared state y = 0

CMSC Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 1 T2 executes, storing the incremented cnt value. Shared state y = 0

CMSC Data Race Example static int cnt = 0; t1.run() { int y = cnt; cnt = y + 1; } t2.run() { int y = cnt; cnt = y + 1; } cnt = 1 T2 completes. T1 executes again, storing the incremented original counter value (1) rather than what the incremented updated value would have been (2)! Shared state y = 0

CMSC What Happened? Different schedules led to different outcomes –This is a data race or race condition A thread was preempted in the middle of an operation –Reading and writing cnt was supposed to be atomic- to happen with no interference from other threads –The second schedule (interleaving of threads) allowed atomicity to be violated –These bugs can be extremely hard to reproduce and debug

CMSC Question If instead of int y = cnt; cnt = y+1; We had written –cnt++; Would the result be any different? Answer: NO! –Don’t depend on your intuition about atomicity

CMSC Question If you run a program with a race condition, will you always get an unexpected result? –No! It depends on the scheduler and on the other threads/processes/etc, that are running on the same machine Race conditions are very hard to find

CMSC Synchronization Mechanisms allowing a programmer to control the execution order of certain operations across different threads in a concurrent program. Different languages have adopted different mechanisms to allow the programmer to synchronize threads. Primary mechanism: locks/mutexes

CMSC Locks (Java) and Mutexes (Ruby) Ruby: Mutex class in Thread library Only one thread can hold a lock at once –Other threads that try to acquire it block (or become suspended) until the lock becomes available class Lock void lock(); void unlock(); end

CMSC Applying Synchronization int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } cnt = 0Shared state T1 acquires the lock

CMSC Applying Synchronization int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } cnt = 0Shared state T1 reads cnt into y y = 0

CMSC Applying Synchronization int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } cnt = 0Shared state T1 is preempted. T2 attempts to acquire the lock but fails because it’s held by T1, so it blocks y = 0

CMSC Applying Synchronization int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } cnt = 1Shared state T1 runs, assigning to cnt y = 0

CMSC Applying Synchronization int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } cnt = 1Shared state T1 releases the lock and terminates y = 0

CMSC Applying Synchronization int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } cnt = 1Shared state T2 now can acquire the lock. y = 0

CMSC Applying Synchronization int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } cnt = 1Shared state T2 reads cnt into y. y = 0 y = 1

CMSC Applying Synchronization int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } cnt = 2Shared state T2 assigns cnt, then releases the lock y = 0 y = 1

Synchronization and Data Races Proper use of locks can prevent data races –All writes to shared memory must be protected by locks –(And some reads, too) Lock granularity refers to the size of memory locations protected by a lock –Small granularity: more concurrency –Large granularity: easier to implement There are analysis tools for finding data races –E.g. Eraser, Valgrind, Locksmith CMSC 330

45 Another Problem: Deadlock Deadlock occurs when no thread can run because all threads are waiting for a lock –No thread running, so no thread can ever release a lock to enable another thread to run Thread 1 l.lock(); m.lock();... m.unlock(); l.unlock(); Lock l = new Lock(); Lock m = new Lock(); Thread 2 m.lock(); l.lock();... l.unlock(); m.unlock(); This code can deadlock… -- when will it work? -- when will it deadlock?

CMSC Deadlock (cont’d) Some schedules work fine –Thread 1 runs to completion, then thread 2 But what if... –Thread 1 acquires lock l –The scheduler switches to thread 2 –Thread 2 acquires lock m Deadlock! –Thread 1 is trying to acquire m –Thread 2 is trying to acquire l –And neither can, because the other thread has it

CMSC Wait Graphs l T1 Thread T1 holds lock l m T2 Thread T2 attempting to acquire lock m Deadlock occurs when there is a cycle in the graph

CMSC Wait Graph Example l T1 m T2 T1 holds lock on l T2 holds lock on m T1 is trying to acquire a lock on m T2 is trying to acquire a lock on l

Deadlock Conditions (Coffman) Mutual Exclusion –At least one resource must be non-sharable Hold and Wait –At least one process must be simultaneously holding and requesting resources No Pre-emption –The operating system cannot (or will not) break the deadlock by killing a process Circular Wait –E.g. wait graph CMSC 330

Dealing with deadlock Ignore it –The “ostrich algorithm” Detect it and recover from it –Kill or roll back a process –Re-allocate a resource Avoid it –Don’t allow resource acquisition if it will lead to deadlock (Banker’s algorithm) Prevention –Remove all possibility of one of the Coffman conditions CMSC 330

51 Classic: Dining Philosophers Problem Philosophers either eat or think They must have two forks to eat Can only use forks on either side of their plate No talking! Avoid deadlock and starvation!

CMSC Bad Dining Philosophers Solution 1 Philosophers all pick up the left fork first Deadlock! –all are holding the left fork and waiting for the right fork

CMSC Bad Dining Philosophers Solution 2 Philosophers all pick up the left fork first Philosophers put down a fork after waiting for 5 minutes, then wait 5 minutes before picking it up again Starvation!

CMSC Possible Solutions The waiter solution –Third party arbiter (scheduler) –Each thread requests permission before acquiring a resource The resource hierarchy solution –Impose ordering on resources –Must obtain resources in order –Most practical solution –Sometimes hard to know in advance

CMSC Dining Philosophers Solution Number the philosophers Start by giving the fork to the philosopher with lower number. Initially, all forks are dirty. When a philosopher wants both forks, he sends a message to his neighbors When a philosopher with a fork receives a message: if his fork is clean, he keeps it, otherwise he cleans it and gives it up. After a philosopher eats, his forks are dirty. If a philosopher had requested his fork, he cleans it and sends it.

CMSC Dining Philosophers Example Each philosopher begins with the forks shown. All are dirty

CMSC Dining Philosophers Example Philosopher 2 sends a message to philosopher 1 that he wants his fork. Their shared fork is dirty, so philosopher 1 cleans it and sends it

CMSC Dining Philosophers Example Philosopher 2 eats! While he is eating philosopher 3 requests their shared fork. Philosopher 2 is done eating, so his forks become dirty

CMSC Dining Philosophers Example Philosopher 2 is done eating, so he honors philosopher 3’s request and cleans the fork and sends it. Philosopher 3 eats!

CMSC Philosophers Implementation Needs Wait until notified about something by another philosopher –stay hungry until you have two forks –hold onto your fork until your neighbor needs it Send a message to a philosopher and have it processed at a later time –multiple philosophers can send messages to one –when philosopher done eating he should process all … and here’s another problem with these needs…

CMSC Producer/Consumer Problem Suppose we are communicating with a shared variable –E.g., some kind of a fixed size buffer holding messages One thread produces input to the buffer One thread consumes data from the buffer Rules: –producer can’t add input to the buffer if it’s full –consumer can’t take input from the buffer if it’s empty

CMSC Producer / Consumer Idea cba If the buffer is partially full, producer or consumer can run: producer consumer If the buffer is empty, only the producer can run: producer If the buffer is full, only the consumer can run: edcba consumer

CMSC Needed Solution Need a way of having threads “wait” on a resource Also need a way to “notify” waiting threads when they can wake up This is usually called a monitor

Ruby Locks Monitor, Mutex –Intended to be used by multiple threads –Methods are executed with mutual exclusion As if all methods are synchronized –Monitor is reentrant, Mutex is not CMSC 330

Ruby Locks Create lock using Monitor.new –Synchronize method takes code block argument require 'monitor.rb’ myLock = Monitor.new myLock.synchronize { # myLock held during this code block } CMSC 330

Ruby Conditions Condition derived from Monitor –Create condition from lock using new_cond –Sleep while waiting using wait_while, wait_until –Wake up waiting threads using broadcast Example myLock = Monitor.new myCondition = myLock.new_cond myLock.synchronize { myCondition.wait_while { y > 0 } myCondition.wait_until { x != 0 } } myLock.synchronize { myCondition.broadcast } CMSC 330

Parking Lot Example require "monitor.rb” class ParkingLot def = = end def addCar end def removeCar end CMSC 330

Parking Lot Example def addCar # do work not requiring < MaxCars + } end def removeCar # do work not requiring > 0 – } end CMSC 330

Parking Lot Example garage = ParkingLot.new valet1 = Thread.new { # valet 1 drives cars into parking lot while do # do work not requiring synchronization garage.addCar end } valet2 = Thread.new { # valet 2 drives car out of parking lot while do # do work not requiring synchronization garage.removeCar end } valet1.join valet2.join CMSC 330

Ruby vs. Java Threads Ruby thread can access all variables in scope when thread is created, including local variables –Java threads can only access object fields Exiting –All threads exit when main Ruby thread exits –Java continues until all non-daemon threads exit When thread throws exception –Ruby only aborts current thread (by default) –Ruby can also abort all threads (better for debugging) Set Thread.abort_on_exception = true CMSC 330

ThreadError To handle a threading error: begin rescue ThreadError ensure end CMSC 330

Review Multiprocessing –Processes vs. threads Problems –Data races/conditions –Deadlock –Dining philosophers –Producers/consumers Tools –Locks/mutexes –Monitors CMSC 33072

CMSC Aside: Functional Programming Pure functional languages –No side effects –No memory access –No data races! Much easier to parallelize functional programs

What’s Next? Extension to existing language... –Universal Parallel C (UPC) –High-Performance Fortran (HPF) –POSIX threads...or an entirely new language? –Chapel (Cray) –X10 (IBM) No clear consensus yet CMSC 330

Summary CMSC 330