1 csc321 §2 concurrent programming abstraction & java threads section 2 concurrent programming...

30
1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

Upload: salma-pickford

Post on 14-Dec-2015

263 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

1CSC321 §2 Concurrent Programming Abstraction & Java Threads

Section 2

Concurrent Programming Abstraction & Java Threads

Page 2: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

2CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1: Concurrent Programming Abstraction

The execution of a concurrent program consists of multiple processes active at the same time. Each process is the execution of a sequential program.

If the computer has multiple PEs then there is parallel or real concurrent execution.

However, with a single PE the processor is switched among the processes. This interleaving is referred to as pseudo-concurrent execution.

Page 3: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

3CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1: Concurrent Programming Abstraction

Without loss of generality, we will always model concurrent execution as interleaved whether or not implementations run on multiple PEs.

l1

l2

l1 l2

Sequences are interleaved.

Page 4: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

4CSC321 §2 Concurrent Programming Abstraction & Java Threads

In most systems absolute time is unimportant.

Systems are frequently upgraded with faster components. Correctness should not depend on absolute time.

Time is ignored only sequences are important.

2.1: Concurrent Programming Abstraction

load add mult

store

load add mult

store

l1 l2

l2 l1

Arbitrary interleaving is allowed.

Program must be correct under all interleavings.

Page 5: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

5CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1: Concurrent Programming Abstraction

In our abstraction, whether on multiple PEs or a single PE, each process is considered to be operating on its own processor, executing its own program. Only two possible interactions to consider:

• contention - competing for a shared resource;

• communication - synchronise (agree that a certain event has to take place).

Page 6: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

6CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1: Concurrent Programming Abstraction

The absolute time taken by an atomic instruction is ignored. Arbitrary interleavings are allowed. The interleaving must be fair i.e. no process is deferred

forever. A concurrent program is required to be correct under all fair

interleavings. Note: Conventional ‘debugging’ to detect and correct errors is impossible

Concurrent programming abstraction is the study of interleaved execution of the atomic instructions of sequential processes.

Page 7: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

7CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.1: Interleaving

Consider the following program:

process P1 p1a; p1b;end P1;

process P2 p2a; p2b;end P2;

What are the possible interleavings ? (an interleaving is sometimes referred to as a history or trace)

p1a; p1b; p2a; p2b;p2a; p2b; p1a; p1b;p1a; p2a; p1b; p2b;p2a; p1a; p2b; p1b;p1a; p2a; p2b; p1b;p2a; p1a; p1b; p2b;

Page 8: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

8CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.1: Interleaving

The number of interleavings in a concurrent program is generally enormous.

Suppose a concurrent program contains n processes and that each executes a sequence of m atomic actions. The number of different interleavings is:

(n.m)!____

(m!)n

Three processes each having two atomic actions will result in 90 possible interleavings.

Page 9: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

9CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.1: Interleaving

Consider the following program:

int c1 = 2;int c2 = 3;

process P1p1: c1 = c1 * c2;end P1;

process P2p2: c1 = c1 + c2;end P2;

What is the meaning of this program? That is, what are the values of c1 and c2 after execution of the program?

Two possible answers:c1 == 9; c2 == 3 if p1 executes before p2c1 == 15; c2 == 3 if p2 executes before p1

Page 10: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

10CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.1: Interleaving

Consider the following program:

process P1p1: continue = false;end P1;

process P2p2: while (continue);end P2;

When there is contention among processes a scheduling policy determines which will execute next.

Suppose a scheduling policy assigns a processor to a process until that process either terminates or delays?

If there is only one processor, is the scheduler fair ?

bool continue=true;

Page 11: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

11CSC321 §2 Concurrent Programming Abstraction & Java Threads

An atomic action makes an indivisible state transition.

2.1.2: Atomic instructions

It is extremely important to define exactly which instructions are being interleaved i.e. which instructions are atomic.

int n=0;

process P1p1: n=n+1;end P1;

process P2p2: n=n+1;end P2;

Consider the following simple program which is being executed on a 2-processor computer. Each PE has its own set of registers.

Page 12: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

12CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.2: Atomic instructions

If the compiler translates n=n+1 into a single INC machine language instruction, any interleaving will give the correct result.

p2: INC n p1: INC n

n==2

p1: INC n p2: INC n

n==2

Page 13: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

13CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.2: Atomic instructions

However, if the computation is performed using a load-store architecture some interleavings will give an incorrect result.

In a load-store architecture values are manipulated by loading them into registers, operating on them and then storing the results back into memory.

p1: load n into Rp2: load n into Rp1: R=R+1p2: R=R+1p1: store R into np2: store R into n

n == 1

Page 14: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

14CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.2: Atomic instructions

The previous example illustrates the lost update problem. This is an example of a race condition.

Race conditions occur when two or more processes share data and the final result, which may be erroneous, depends on the interleaving of the processes’ atomic actions.

Problem: A bank has 10,000 accounts. Each account has exactly £1,000. Periodically, an ATM process picks two accounts at random and moves a random amount of money from one to the other. Periodically, an Auditor process totals the banks assets to check for embezzlement of funds.

What might happen ?

Page 15: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

15CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.2: Atomic instructions

int y=0;

int z=0;

process P1 int x;1a: x=y+z;end P1;

process P22a: y=1;2b: z=2;end P2;

Assuming a load-store architecture i.e.

Instruction 1a is implemented as:Load y into RAdd z to RStore R into x

what are the possible final values of x in the following program ?

Page 16: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

16CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.2: Atomic instructions

int y=0;

int z=0;

process P1 int x;1a: R=y;1b: R=R+z; 1c: x=R; end P1;

process P22a: y=1;2b: z=2;end P2;

2a;2b;1a;1b;1c

2a;1a;2b;1b;1c

2a;1a;1b;2b;1c

2a;1a;1b;1c;2b

1a;2a;2b;1b;1c

1a;2a;1b;2b;1c

1a;2a;1b;1c;2b

1a;1b;2a;2b;1c

1a;1b;2a;1c;2b

1a;1b;1c;2a;2b

We could enumerate all 10 interleavings and evaluate x at the end of each. Alternatively we could try and reason about the program.

Page 17: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

17CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.2: Atomic instructions

int y=0;

int z=0;

process P1 int x;1a: R=y;1b: R=R+z; 1c: x=R; end P1;

process P22a: y=1;2b: z=2;end P2;

The shared variable y is only modified in one place in P2 (2a) and only used in one place in P1 (1a). We must therefore consider two cases:

2a..1a and 1a..2a

The shared variable z is only modified in one place in P2 (2b) and only used in one place in P1 (1b). Therefore, within the cases above we must also consider:

2b..1b and 1b..2b

<-2b->

2a...1a…1b

x=3 (2 interleavings)

2a...1a…1b..2b

x=1 (2 interleavings) <-1b->

1a...2a…2b

x=0 (? interleavings)

1a...2a…2b..1b

x=2 (1 interleaving)

Page 18: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

18CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.3: Correctness

Partial correctness: a program is partially correct if the final state is correct assuming the program terminates.

Total correctness: a program is totally correct if it always terminates with a correct answer.

Partial correctness and total correctness are appropriate for concurrent programs which terminate just as they are for sequential programs.

In addition, the correctness of concurrent programs is defined in terms of properties of execution sequences. There are two types of correctness properties:

safety properties;

liveness properties.

Page 19: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

19CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.1.3: Correctness

Safety properties: the property must always be true (nothing bad will ever happen).Mutual exclusion: processes may not interleave certain

sub-sequences of instructions e.g. at most one process is permitted to access a printer at any one instance.

Absence of deadlock: deadlock occurs when all processes are blocked and are unable to proceed.

Liveness properties: the property must eventually be true (something good will eventually happen).Absence of starvation e.g. if a process posts a request to

print, eventually it will be assigned a printer.

Page 20: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

20CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2: Java Threads

either its own run() method; or the run() method of a some other object.

In Java a process is represented by a thread. To make a thread run you call its start() method. This registers the thread with the thread scheduler.

The scheduler, which may be part of the JVM or the host operating system, determines which thread is actually running in the CPU at any given time.

Calling the start() method does not cause the thread to run immediately; it only makes it eligible to run. The thread must contend with other threads for the CPU.

When a thread gets to execute, it executes a run() method:

Page 21: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

21CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.1: Executing a Thread

class Interleave { public static int c1 = 2; public static int c2 = 3; public static void main (String[] args) { Thread p1 = new P1 (); Thread p2 = new P2 (); p1.start (); p2.start (); }}

class P1 extends Thread { public void run () { Interleave.c1 = Interleave.c1 *Interleave .c2; }} class P2 extends Thread { public void run () { Interleave.c1 = Interleave.c1 +Interleave.c2; }}

Extend the Thread class and override its run() method.

Page 22: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

22CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.1: Executing a Thread

class Interleave { public static int c1 = 2; public static int c2 = 3; public static void main (String[] args) { Thread p1 = new Thread(new P1()); Thread p2 = new Thread(new P2()); p1.start (); p2.start (); }}

class P1 implements Runnable { public void run () { Interleave.c1 = Interleave.c1 *Interleave .c2; }} class P2 implements Runnable { public void run () { Interleave.c1 = Interleave.c1 +Interleave.c2; }}

Sometimes it is desirable to implement the run() method in a class not derived from Thread but from the interface Runnable.

Page 23: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

23CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.1: Executing a Thread

A dead thread cannot be restarted. A dead thread’s methods can be called.

When the run() method ends the thread is considered dead. A dead thread cannot be started again, but it still exists and, like any other object, its methods and data can still be accessed.

Page 24: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

24CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.2: Thread States

When a thread’s start() method is called, the thread goes into a ready-to-run state and stays there until the scheduler moves it to the running state. In the course of execution the thread may temporarily give up the CPU and enter some other state.

Running

Monitor states

Ready

Suspended Asleep Blocked

Page 25: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

25CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.2: Thread states - Yielding

A thread can offer to move out of the CUP by yielding. A call to the static yield() method causes the currently executing thread to move to the Ready state.

If there are any other threads in the Ready state, the thread that just yielded may have to wait before it gets to execute again. If there are no waiting threads in the Ready state the thread that just yielded will get to continue executing immediately.

Running

Ready

Thread.yield() scheduled

Page 26: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

26CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.2: Thread states - Sleeping

A call to the static sleep() method requests the currently executing thread to cease executing for an approximately specified period in milliseconds.

scheduled

Running

Ready

Thread.sleep(20)

Asleep

time expires or interrupted

Note: when the thread finishes sleeping (20 milliseconds) it does not continue execution directly.

The Thread class has an interrupt() method. A sleeping thread that receives an interrupt() call moves immediately into the Ready state; when it gets to run it will execute its InterruptedException handler.

Page 27: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

27CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.2: Thread states - Blocking

If a method needs to wait for an indeterminable amount of time until some I/O occurrence takes place it should step out of the Running state. This is know as blocking. All Java I/O methods behave this way.

scheduled

Running

Ready

blocking method

Blocked

Blocking condition changes or interrupted

A thread can also become blocked if it fails to acquire the lock for a monitor or if it issues a wait() call. This will be explained later.

Page 28: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

28CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.2: Thread states - Suspending, Resuming and Stopping

The suspend() method allows any arbitrary thread to make another thread un-runnable for an indefinite period of time.

The suspended thread becomes runnable when some other thread resumes it using the resume() method.

The stop() method allows any arbitrary thread to kill another thread.

These three methods are now deprecated. They should be avoided as they are unsafe and can easily lead to deadlock.

Page 29: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

29CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.3: Thread Priorities and Scheduling

Every thread has a priority (from 1..10). All newly created threads have their priority set to that of the creating thread. Higher priority threads get preference over lower priority threads.

The scheduler generally chooses the the highest-priority waiting thread. If there is more than one waiting thread the scheduler chooses one of them: there is no guarantee that the one chosen is the one that has been waiting longest.

int oldPriority = aThread.getPriority();

int newPriority = Math.min(oldPriority+1,

Thread.MAX_PRIORITY);

aThread.setPriority(newPriority);

Note: The way thread priorities affect scheduling is platform dependent.

Page 30: 1 CSC321 §2 Concurrent Programming Abstraction & Java Threads Section 2 Concurrent Programming Abstraction & Java Threads

30CSC321 §2 Concurrent Programming Abstraction & Java Threads

2.2.3: Thread Priorities and Scheduling

Preemptive scheduling (Solaris, Windows pre JDK1.0.2) - A thread runs until: it leaves the Running state by yielding, blocking, sleeping

etc; it gives way to a higher-priority thread.

Time-sliced (Mac, Windows with JDK 1.0.2) - A thread is allowed to execute for a limited amount of time (approximately 100 milliseconds). It is then moved into the Ready state where it must contend with all other ready threads.

Historically, two approaches have emerged for implementing thread schedulers.