240 likes | 368 Views
Project 2 Overview (Threads in Practice). CSE451 Andrew Whitaker. Project 2 Overview. Project consists of threaded Java programs No VMWare / kernel hacking You can use any multi-processor Linux machine Most (all?) undergrad lab machines are dual core
E N D
Project 2 Overview(Threads in Practice) CSE451 Andrew Whitaker
Project 2 Overview • Project consists of threaded Java programs • No VMWare / kernel hacking • You can use any multi-processor Linux machine • Most (all?) undergrad lab machines are dual core • Also, you have access to amlia.cs.washington.edu • Run ‘more /proc/cpuinfo’ to verify • Continue to work in your project teams
General Instructions • Your programs must use proper synchronization • Working functionality is not enough! • Remember the rules we’ve talked about: • All shared, mutable state must be properly synchronized • Usually with a synchronized block or method • Compound actions must be protected by a single lock • Start early! • Not a huge amount of code, but a lot of new concepts • Thursday’s discussion will be Q & A
Using Other People’s Code • Do it! • e.g., java.util.LinkedList, java.util.ArrayList, … • But, understand the implications for threading • May require documentation diving
Part 1: Implementing Semaphores • Semaphore is a thread-safe integer • Supports up and down operations for increment / decrement • The semaphore can never go negative • If value == 0, then down blocks before decrementing • Thread is added to a wait queue • If value == 0, then up wakes up a thread after incrementing • Semaphore with value 1 is a lock
Pseudocode publicclass Semaphore { private int count; // block if count == 0 // else, decrement publicvoid down () { } // increment count // wake up somebody (if necessary) publicvoid up () { } }
Semaphores, Continued • Condition variables and semaphores have equivalent expressive power • One can be implemented with the other • Your task: demonstrate this with Java code • Your solution should not busy wait • Do not use java.util.concurrent.Semaphore • Or any other off-the-shelf semaphore implementation
Part 2: Calculating • Step 1: approximate using a random number generator • Step 2: Convert this program to a multi-threaded program • Step 3: Benchmark the program with a variable number of threads
Approximation Hint • Consider a circle inscribed in a square • Imagine throwing a large number of darts at the square • Some fraction of darts will also hit the circle • Use this fraction to calculate
Multi-threaded Calculator • Approximating requires many samples • 10s of millions is a reasonable starting point • So, let’s try decomposing the work across multiple threads public double calculate(int numSamples, int numThreads) { return 0.0; // TODO: implement this! }
Mapping This to Code • Java’s Thread join method is useful for these sorts of computations public double calculate(int numSamples, int numThreads) { Thread [] threads = new Thread[numThreads]; for (int i=0;i <= numThreads; i++) { threads[i] = new WorkerThread(…); threads[i].start(); } for (int i=0;i <= numThreads; i++) { try { threads[i].join(); // wait for thread termination } catch (InterruptedException ie) {} //ignored } }
Benchmarking • Create a graph with # threads on the x-axis and latency on the y-axis • Let threads range from 1 to 10 • Number of samples should be fixed • Each thread does a fraction of the total samples • Measure latency with System.currentTimeMillis()
Part 3: Multi-threaded Web Server • Task: convert a single-threaded web server to a multi-threaded web server • Why? • Any high-throughput web server must handle multiple requests in parallel • By default, each thread handles one request at a time • Requests are blocking • Thread is stalled while waiting for network, disk, etc.
These are blocking calls Anatomy of a (Single-threaded) Web Server • Accept a new Socket • Read from socket to extract request URI (e.g., index.html) • Read desired file into a buffer • Write file over the socket • Close the socket while (true) { }
Possible Alternate Approach: Thread-per-request while (true) { • Accept a new Socket • Fork a thread } Read from socket Read desired file into a buffer Write file over the socket Close the socket Thread exits
Analysis of Thread-per-Request • Advantage: supports simultaneous requests (and higher throughput) • Blocking operations only stall one thread • Disadvantages: • Thread creation is expensive • Must create PCB, allocate stack • Thread teardown is expensive • Too many threads can lead to poor performance
Preferred Solution: Thread Pool • On startup, create a static pool of worker threads • Each thread loops forever, processing requests • Advantages: • Thread allocation cost is paid only once • Threads are never deallocated
Thread Pool, Implementation Overview while (true) { • Accept a new Socket • Enqueue Socket while (true) { } Dequeue Socket Read from socket Read desired file into a buffer Write file over the socket Close the socket Accept thread } Worker threads
Web Server, Continued • Step 2: Add a “statistics” page at http://hostname/STATS • Req/sec over the previous ten seconds • Number of currently active threads • Number of idle threads • Step 3: Benchmark the web server • Using the provided benchmark tool
Java Timers • See lecture or condition variables • OR, java.util.Timer and java.util.TimerTask • Key point: timers run in a separate thread • So, shared state must be properly synchronized
Part 4: GUI Hacking • We provide a simple GUI for calculating the first N fibonacci numbers • You provide an implementation of the cancel button
Challenge • Problem: GUI frameworks are single-threaded • Long-lived computations can make the GUI unresponsive • Solution: Transfer long-lived tasks to a separate thread • Requires coordination between the GUI thread and the helper thread
Things You Need to Understand • How task handoff works in the Swing GUI framework? • In particular, SwingUtilities.invokeLater • How does thread interruption work? • Via Thread.interrupt
Thread Interruption • You can call interrupt on any Thread • What happens? • If the thread was blocked, it receives an InterruptedException • If the thread is ready or running, it has an interrupted flag set • The thread must explicitly check this flag with Thread.isInterrupted