Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Programming with Concurrent Threads Robert M. Dondero, Ph.D. Princeton University 1 Objectives You will learn/review: What a thread is How to spawn and join threads How to handle threads that access shared objects Race conditions and prevention of them Deadlocks and prevention of them How to interrupt threads How threads can communicate 2 Definition of Thread A process is an instance of a running program A thread is a flow of control within a process A process contains one or more threads Within a process, all threads: Execute concurrently Share global data (data in the heap section, data section, and bss section) 3 Concurrency Options To implement concurrency... Option 1: Multiple processes Process P1 forks process P2 P1 and P2 execute concurrently P1 and P1 do not share objects Expensive context switching 4 Concurrency Options Option 2: Multiple threads Within P1, thread T1 spawns thread T2 T1 and T2 execute concurrently T1 and T2 share P1’s objects Inexpensive context switching 5 Processes vs. Threads Concurrent Processes Running Same Program PROCESS 1 HEAP STACK PROCESS 2 RODATA STACK DATA HEAP DATA TEXT BSS BSS IP REG IP REG 6 Processes vs. Threads (cont.) Concurrent Threads within Same Process THREAD 1 STACK THREAD 2 RODATA DATA HEAP BSS IP REG STACK IP REG TEXT 7 The Usefulness of Threads Example: Java virtual machine process JVM process must execute given program JVM process also must collect garbage Example: server process Server process must communicate with client process continuously Server process also must allow other client processes to connect 8 The Usefulness of Threads Example: browser process Browser process must fetch (large) web pages Browser process also must respond to user input 9 Spawning Threads The "main" thread executes at process startup Other threads may execute also The main thread can spawn other threads Note terminology: One process "forks" another One thread "spawns" another 10 Spawning Threads in Java See Spawning.java To spawn a thread: Define a subclass of Thread Override run() method Create an object of that class To begin execution of a thread: Call object's start() method start() calls run() Don’t call run() directly 11 Spawning Threads in Java See RunnableInterface.java Alternative way to spawn a thread: Define class that implements Runnable Must define a run() method Create a Thread object specifying Runnable object as argument 12 Spawning Threads in Java To begin execution: Call Runnable object’s start() method start() calls run() Don't call run() directly Useful when class extends some class other than Thread 13 Spawning Threads in Python See spawning.py (Much the same as Java) No need for "Runnable interface" approach Python supports multiple inheritance 14 Joining Threads Main thread can join a child thread Main thread can block until child thread exits Terminology A parent process can "wait" for a child process A parent thread can "join" a child thread 15 Joining Threads in Java See Joining.java thread.join() Blocks current thread until thread terminates May throw InterruptedException (Explained later) 16 Joining Threads in Python See joining.py (Much the same) 17 Race Conditions Problem: Threads share objects Danger if multiple threads update same object Race condition Outcome depends upon thread scheduling See RaceCondition.java See racecondition.py 18 Locking Solution: Locking Current thread gets lock on shared object Other threads cannot obtain lock on shared object until current thread releases lock Adds lots of overhead 19 User-Level Locking Approach 1: Locking in user of shared object 20 User-Level Locking in Java See LockInUser.java synchronized(sharedobj) { stmt; stmt; …} Current thread: "Make sure I have the lock on sharedobj" Other threads cannot obtain lock on sharedobj during execution of block 21 User-Level Locking in Python See lockinuser.py First create a lock bankLock = allocate_lock() Then, in each thread: self._bankLock.acquire() Current thread: "Give me the lock on sharedobj" Use shared object self._bankLock.release() 22 Resource-Level Locking Approach 2: Locking in shared resource/object itself 23 Java Resource-Level Locking See LockInResource.java public synchronized void method() {…} Is the same as: public void method() { synchronized(this) {…} } Bank object thus is thread-safe 24 Py Resource-Level Locking See lockinresource.py Same, except... Locking is performed by bank object rather than by thread objects Bank object thus is thread-safe 25 Locking Strategies Which locking approach is better? Resource-level locking Safer; shared object is thread-safe User-level locking Maybe faster Avoids using locks when unnecessary Recall Java Vector class vs. ArrayList and SynchronizedList classes 26 Conditions Problem: Thread may need to wait for some condition on a locked object to become true Example: Withdraw thread must wait for bank balance to be sufficiently large Solution: Conditions 27 Conditions Called from within locked code… object.wait() Blocks current thread until it is notified Releases lock object.notifyAll() Notifies all waiting threads That some significant event has occurred Thread then should re-check condition 28 Conditions Pattern Thread conditions pattern: consumer() while (! condition) wait(); // Do what should be done when // condition is true. producer() // Change condition. notifyAll(); 29 Java Conditions See Conditions.java Consumer method calls object.wait() repeatedly until condition is true Producer method calls object.notifyAll() Could handle conditions in users rather than in shared resource 30 Python Conditions See conditions.py Condition wraps around lock Could handle conditions in users rather than in shared resource 31 Deadlock Problem: deadlock Two threads: t1 and t2 Two shared objects: o1 and o2 t1 has lock on o1; needs lock on o2 t2 has lock on o2; needs lock on o1 Both threads block forever 32 Java Deadlock Example See Deadlock.java Deadlock (1) run() (2) run() chatThreadAlice chatThreadBob (3) chat() alice (4) chat() (5) chatBack() bob (6) chatBack() 33 Python Deadlock Example See deadlock.py (Same formula) 34 Preventing Deadlock Solution System does not – and cannot – prevent deadlock Must design carefully to avoid deadlock 35 Java Preventing Deadlock See NoDeadlock.java NoDeadlock (1) run() chatThreadAlice (3) chat() alice (2) run() PersonMutex (5) get lock chatThreadBob (7) get lock (6) chatBack() (8) chatBack() (4) chat() bob 36 Python Preventing Deadlock See stilldeadlock.py Still deadlock! Note subtle difference in locking semantics Java: "Make sure I have the lock" Python: "Give me the lock" See nodeadlock.py Must do user-level locking 37 Interrupting Threads Bad idea to end a thread abnormally May leave shared objects in inconsistent states How to force normal thread termination? That is, how to force normal return from run()? 38 Interrupting Threads Forcing normal thread termination Define isInterrupted flag in thread object Define public thread.setInterrupted() method Initially set to false Called to set isInterrupted flag to true run() checks isInterrupted flag periodically true => return from run() 39 Interrupting Threads Problem What if thread is joining/waiting/sleeping? Solution Interrupting threads… 40 Java Interrupting Threads thread.interrupt() Sets flag If thread is joining, waiting, or sleeping... join(), wait(), or sleep() throws InterruptedException catch clause should forward interrupt to current thread Thread.interrupted() Checks flag of current thread Unsets flag 41 Java Interrupting Threads Pattern: try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } See Interrupting.java 42 Python Interrupting Threads Not supported!!! (Java is particularly good for multithreaded programming) 43 Thread Communication Facts: Threads can communicate via shared objects Communication via shared objects is dangerous Often threads are in a producer/consumer relationship Is there a safer way for producer/consumer threads to communicate? 44 Java Thread Comm ProducerThread PipedOutputStream ConsumerThread PipedInputStream PipedOutputStream and PipedInputStream • Allow producer thread to send data to consumer thread • See also java.io.PipedWriter and PipedReader for sending Unicode characters See ProdConStream.java 45 Python Thread Comm See prodconstream.py No "stream" mechanism Can't implement Unix model Instead... Queue class Methods are "synchronized" Producer thread "puts" to queue object Consumer thread "gets" from queue object 46 Threads Editorial Today, threads are essential Garbage collection, GUI pgmming, network pgmming, Web pgmming, ... Threads can be dangerous!!! Threads share data, bss, heap sections Avoid shared objects!!! 47 Threads Editorial Should "synchronized" be the default? Should safety or speed have priority? Are threads a passing phase? Summary We have covered: What a thread is How to spawn and join threads How to handle threads that access shared objects Race conditions and prevention of them Deadlocks and prevention of them How to interrupt threads How threads can communicate 49 Appendix 1: Threads in C 50 Threads in C C language does not support threads C standard library does not support threads Use non-standard "pthreads" library Not object-oriented; uses function pointers Specify “-pthread” option to gcc command 51 Threads in C An error-handling module See mypthread.h See mypthread.c Spawning threads See spawning.c 52 Threads in C Joining threads See joining.c Locking See lockinuser.c See lockinresource.c Conditions See conditions.c 53 Threads in C Deadlock See deadlock.c See nodeadlock.c Interrupting (Not available in C) Thread communication (Omitted) 54 Appendix 2: Daemon Threads 55 Daemon Threads User thread (as seen so far) Process exits when all user threads have terminated Example: thread that calls main() Daemon thread Exists only to service other threads Process can terminate with running daemon threads Example: garbage collector thread 56 Daemon Threads thread.setDaemon(b) thread.isDaemon() Sets daemon status of thread to b (true or false) Returns daemon status of thread See Daemons.java Daemon threads end when main thread ends 57