Project 2 Overview (Threads in Practice)
Download
Report
Transcript Project 2 Overview (Threads in Practice)
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
public class Semaphore {
private int count;
// block if count == 0
// else, decrement
public void down () { }
// increment count
// wake up somebody (if necessary)
public void 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 multithreaded 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 xaxis 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.
Anatomy of a (Single-threaded)
Web Server
while (true) {
1. Accept a new Socket
2. Read from socket to extract
request URI (e.g., index.html)
3. Read desired file into a buffer
4. Write file over the socket
5. Close the socket
}
These are
blocking calls
Possible Alternate Approach: Threadper-request
while (true) {
1. Accept a new Socket
2. Fork a thread
}
1. Read from socket
2. Read desired file into a buffer
3. Write file over the socket
4. Close the socket
5. 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) {
1.
2.
Accept a new Socket
Enqueue Socket
while (true) {
}
1.
2.
3.
4.
5.
Accept thread
Dequeue Socket
Read from socket
Read desired file into a buffer
Write file over the socket
Close the socket
}
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 singlethreaded
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