190 likes | 395 Views
Threads. CSE451 Andrew Whitaker. What is a Thread?. Thread : A “virtual CPU” that can be scheduled for execution Each thread has its own “main” routine Each thread has its own set of registers Process : A thread + an address space. Firefox. Threaded Hello World.
E N D
Threads CSE451 Andrew Whitaker
What is a Thread? • Thread: A “virtual CPU” that can be scheduled for execution • Each thread has its own “main” routine • Each thread has its own set of registers • Process: A thread + an address space Firefox
Threaded Hello World public class HelloWorld extends Thread { public void run () { System.out.println(“Hello World”); } public static void main (String [] args) { Thread t1 = new HelloWorld(); Thread t2 = new HelloWorld(); t1.start(); t2.start(); } }
Firefox CPU1 CPU2 Why Use Threads? • Threads allow a single program to take advantage of multiple CPUs
These calls might block Why Use Threads: Blocking I/O • Long operations cause a thread to block • e.g., disk reads public void webServer () { readRequest(); readDataFromDisk // Millions of cycles writeDataOverNetwork; // Millions of cycles } • …But, other threads in the process can keep running • This is useful even on a uniprocessor
What Can Go Wrong With Threads? • Safety hazards • “Program does the wrong thing” • Liveness hazards • “Program never does the right thing” • e.g., deadlock • Performance hazards • Program is too slow due to excessive synchronization
Review: Thread Scheduling • Scheduler decides when to run threads • Programs should make no assumptions about the scheduler • Scheduler is a “black box” 1 2 3 4 5 scheduler {4, 2, 3, 5, 1, 3, 4, 5, 2, …} {1, 2, 3, 4, 5, 1, 2, 3, 4, …} CPU
Thread Safety • Definition: A program is thread safe if it behaves “correctly” when accessed from multiple threads • Race condition: program’s output is different depending on scheduler interleavings • Almost always a bug
public class ThreadTest extends Thread { private static int x = 7; public void run () { x++; } public static void main (String [] args) { Thread t1 = new ThreadTest(); Thread t2 = new ThreadTest(); t1.start(); t2.start(); try { t1.join(); // wait for thread to finish t2.join(); // wait for thread to finish } catch (InterruptedException iex) { } System.out.println("Value of x: " + x); } }
Safety Hazard: Incrementing x • Key point: x++ is multiple operations • Load x from memory; increment; store • Or, in MIPS assembly: lw $t, offset($s) addi $t, $t, 1 sw $t, offset($s)
Unsafe Thread Schedule • Given Thread 1 and Thread 2: lw $t, offset($s) // load x into register $t lw $t, offset($s) // load x into register $t addi $t, $t, 1 // add one to the register sw $t, offset($s) // store register to memory addi $t, $t, 1 // add one to register sw $t, offset($s) // store register to memory time Final result?
Solution #1: Synchronized Block public class ThreadTest extends Thread { private static int x = 7; private static Object lockObject = new Object(); public void run () { synchronized(lockObject) { // only one thread can execute in here! x++; } } // … }
Vocabulary • Atomic: Section of code that executes without interleaving instructions from other threads • “all-or-nothing” execution • Critical Section: Section of code that accesses a shared resource • Must be accessed atomically
Note: not synchronized! Solution #2: Atomic Variable public class ThreadTest extends Thread { private static final x = new AtomicInteger(); public void run () { x.incrementAndGet(); } // … }
Rule #1 • All shared, mutable state must be properly synchronized • Usually with a synchronized block or method • Key challenge: figuring out which state is shared and mutable • … More on this to come
Rule #2 • Compound actions must be protected by a single lock
Firefox thread 1 Firefox thread 2 File system read OS DMA Controller disk