Preliminary question. What is a program?
some operations may depend out the outcomes of other operations, others may be independent:
a1 = b1 + c1;
a2 = b2 - c2;
p = a1 * a2
A thread is a sequence of operations—think subprogram
Goal. Partition a program into multiple (logically indpendent) threads.
Payoff. Different threads can be executed in parallel (on parallel computer architecture)
Challenges.
Steps to writing a multithreaded program
Runnable
object
Runnable
interfacevoid run()
run()
defines what your thread should doThread
instance initialized with an instance of your Runnable
objectA thread that increments a counter a bunch of times.
Runnable
Objectpublic class CounterThread implements Runnable {
private Counter counter; private long times;
public CounterThread (Counter counter, long times) {
this.counter = counter; this.times = times;
}
public void run () {
for (long i = 0; i < times; i++) {
counter.increment();
}
}
}
public class Counter {
private long count = 0;
// return the current counter value
public long getCount () { return count; }
// increment the counter
public void increment () { ++count; }
// reset the counter value to 0
public void reset () { count = 0; }
}
Step 2. Create a Thread
instance initialized with an instance of your Runnable
object
Step 3. Start the thread
Step 4. (optional) Wait for the thread to complete
CounterExample.java
CounterExample
with NUM_THREADS
set to 1. What happens?CounterExample
with NUM_THREADS
set to 2.
NUM_THREADS
set to 4, 8, 16, 1000, 1000…What happened with final counts as number of threads increased?
What happend with running times?
Why did this behavior occur?
Computer has two main components
CPU Capabilities:
Memory stores:
Random Access Machine (RAM) model interactions:
Counter
object is stored in memory
Counter
stores a value count
CountThread
instructions stored in memoryWhen CounterThread
is executed, it follows these instructions
for (long i = 0; i < times; i++) {
counter.increment();
}
In turn:
public void increment () { ++count; }
What are CPU/Memory interactions when counter.increment()
is executed?
public void increment () { ++count; }
Modern computers:
increment
operation on different coresincrement
same Counter
concurrentlySuppose: count = 7
& two threads both call increment()
concurrently
What are the possible outcomes? What are results of different read/write operations?
Parallel Random Access Machine (PRAM)
read(i)
and write(i, val)
read
/write
operations are atomic
Nondeterminism:
if multiple threads access same memory location simultaneously all “consistent” outcomes are possible
two processes call write(i, a)
and write(i, b)
one process calls read(i)
another write(i, a)
Consider: How could we avoid the CounterExample
weirdness (nondeterminacy) and get a correct count with multiple threads?
More on nondeterminacy!