(Threads in Practice)

cavalcadejewelSoftware and s/w Development

Nov 18, 2013 (3 years and 11 months ago)

86 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


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 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.



Anatomy of a (Single
-
threaded)
Web Server

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


while (true) {

}

These are

blocking calls

Possible Alternate Approach: Thread
-
per
-
request

1.
Accept a new Socket

2.
Fork a thread

while (true) {

}

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

1.
Accept a new Socket

2.
Enqueue Socket

while (true) {

}

1.
Dequeue Socket

2.
Read from socket

3.
Read desired file into a buffer

4.
Write file over the socket

5.
Close the socket

while (true) {

}

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