308 203 A Introduction to Computing II Lecture

  • Slides: 21
Download presentation
308 -203 A Introduction to Computing II Lecture 18: Concurrency Issues Fall Session 2000

308 -203 A Introduction to Computing II Lecture 18: Concurrency Issues Fall Session 2000

From last time We’ve seen how it is often natural to write programs with

From last time We’ve seen how it is often natural to write programs with multiple “threads” running at the same time. This introduced some issues: • Race conditions: threads may execute at different speeds • Data hazards: threads which share data must “synchronize” accesses to that data to avoid potential data corruption • These things happen in an indeterminite, spontaneous and unpredictable way, governed only by Murphy’s Law

Taking Control of Threads We can make this process less haphazard by letting threads

Taking Control of Threads We can make this process less haphazard by letting threads control their execution. One way to do this in Java is with the sleep( ) method, which causes the calling thread to stop running for a fixed period of time in msec: e. g. sleep(5000) ; // wake up in 5 seconds

Taking Control of Threads A smoother way to allow other threads to run without

Taking Control of Threads A smoother way to allow other threads to run without specifying a specific time to wait is yield( ). Example two threads running the following code: run( ) { for (int j=0; j < 5; j++) { System. out. println(j); yield( ); } }

Taking Control of Threads A smoother way to allow other threads to run without

Taking Control of Threads A smoother way to allow other threads to run without specifying a specific time to wait is yield( ). Example two threads running the following code: run( ) { for (int j=0; j < 5; j++) { System. out. println(j); yield( ); } } Most likely output: 1 1 2 2 3 3

Taking Control of Threads Another way to control thread execution is with priorities: •

Taking Control of Threads Another way to control thread execution is with priorities: • public final static int MIN_PRIORITY = 1; • public final static int NORM_PRIORITY = 5; • public final static int MAX_PRIORITY = 10; The paradigmatic example is a flight-control system with two tasks: • Don’t-Crash-Into-The-Mountain task (high priority) • Copilot’s-Tetris-Game task (low priority)

Priorities Introduce Issues Q. Should high priority tasks always run over lower priority tasks,

Priorities Introduce Issues Q. Should high priority tasks always run over lower priority tasks, or should it be merely preferential?

Priorities Introduce Issues Q. Should high priority tasks always run over lower priority tasks,

Priorities Introduce Issues Q. Should high priority tasks always run over lower priority tasks, or should it be merely preferential? A. In Java, priority is strict, and a higher-priority thread cannot even give precedence to lower-priority threads by yield-ing The consequences of a priority policy can sometimes be devastating…

Starvation Let’s say the “Don’t-Crash-Into-The-Mountain” task never sleeps… The “Copilot’s-Tetris-Game” task will never run.

Starvation Let’s say the “Don’t-Crash-Into-The-Mountain” task never sleeps… The “Copilot’s-Tetris-Game” task will never run. Result: It is very important for higher priority tasks to intentionally sleep or otherwise release the processor periodically.

From last time Data hazards were resolved by “mutually exclusive” access to methods labelled

From last time Data hazards were resolved by “mutually exclusive” access to methods labelled as synchronized: • Sychronized code is effectively executed as a unit, such that other threads cannot simultaneously enter potentially dangerous “critical sections” simultaneously • This also may be dangerous…

The Dining Philosophers A group of philosophers are seated around a table, each with

The Dining Philosophers A group of philosophers are seated around a table, each with a bowl or rice. Between every two philosophers is one chopstick. Most of the time the philosophers contemplate, but periodically they grow hungry and decide to eat. • To eat, a philospher must have both neighboring chopsticks. • Only one chopstick may be picked up at a time. • Once a philosopher picks up a chopstick, she keeps it until finished eating

The Dining Philosophers

The Dining Philosophers

The Problem Suppose each philosopher simultaneously grabs the chopstick to her left… Now everyone

The Problem Suppose each philosopher simultaneously grabs the chopstick to her left… Now everyone has ONE chopstick but no one can eat!

The Dining Philosophers

The Dining Philosophers

The Dining Philosophers Possible solutions: • Leave one chair empty • Pick up both

The Dining Philosophers Possible solutions: • Leave one chair empty • Pick up both chopsticks simultaneously • Have some philosophers always pick up the left chopstick first while others always pick up the right one first

Deadlock This phenomenon is generically refered to as Deadlock It can occur when concurrent

Deadlock This phenomenon is generically refered to as Deadlock It can occur when concurrent threads compete to acquire exclusive resources of various kinds. In general, deadlocks correspond to cycles in wait-graphs, e. g. “A” waits for “B” waits for “C” waits for “A” wait-for A B wait-for C

From Dining Philosohers to “Synchronized” Methods Unfortunately, “synchronized” methods can do exactly that: class

From Dining Philosohers to “Synchronized” Methods Unfortunately, “synchronized” methods can do exactly that: class Foo { synchronized int f( Foo other. Foo ) { return other. Foo. g( ); } synchronized int g( ) { return 0; } }

From Dining Philosohers to “Synchronized” Methods Unfortunately, “synchronized” methods can do exactly that: Let

From Dining Philosohers to “Synchronized” Methods Unfortunately, “synchronized” methods can do exactly that: Let there be: Foo x = new Foo( ) ; Foo y = new Foo( ) ; And two threads which simultaneously do the following: THREAD A: THREAD B: x. f(y) y. f(x)

From Dining Philosohers to “Synchronized” Methods Unfortunately, “synchronized” methods can do exactly that: 1.

From Dining Philosohers to “Synchronized” Methods Unfortunately, “synchronized” methods can do exactly that: 1. THREAD A: x. f(y) => Thread A locks x 2. THREAD B: y. f(x) => Thread B locks y 3. THREAD A: We can’t call y. g( ) without the lock for y 4. THREAD B: We can’t call x. g( ) without the lock for x

The Worst of Both Worlds Combining priorities with mutual-exclusion can lead to hard-to-debug phenomena,

The Worst of Both Worlds Combining priorities with mutual-exclusion can lead to hard-to-debug phenomena, like the case of the priority inversion bug in the Mars Pathfinder, 1997. For details, check out http: //www. time-rover. com/Priority. html

Any questions?

Any questions?