Network Programming - RMIT...

33
Network Programming COSC 1176/1179 Lecture 6 Concurrent Programming (2)

Transcript of Network Programming - RMIT...

Network ProgrammingCOSC 1176/1179

Lecture 6

Concurrent Programming (2)

2NetProg 6 2

Threads

• Recall from last week– Every line of Java code is part of

a thread

– There can be one or more threads running in parallel

– Each thread has its own program counter (pointing to the current instruction being executed)

– All threads in a process share the execution environment

• Advantages of threads– Simpler program design

– More responsive programs

• Disadvantages– Context switching overhead

– Increased resource consumption

Concurrency and parallelism

Image source:http://www.nyu.edu/classes/jcf/g22.3033-007_sp01/handouts/g22_3033_h52.htm

3NetProg 6 3

Multithreading

• Operating system support for multithreading

– Simplifies the application code

– Allows more complex program execution

• Different threads may share a single CPU

– Threads can

• be interrupted to allow another thread to run (preemptive

scheduling)

• voluntarily give up control (e.g. when waiting for data from a socket)

• Different threads can run on different cores of a CPU

– Allows faster execution

Image source: http://blog.takipi.com/java-thread-magic-tricks/

4

Thread Risks

• Safety – Threads need sufficient synchronization, because

• The ordering of operations is unpredictable: the compiler, processor and runtime can reorder and time actions as they see fit (as long as it does not affect the result within the thread)

• Threads can access and modify variables that other threads are using

• Liveness– A thread should not get into a state that it cannot

make forward progress

• Performance– Runtime overhead (e.g. context switching, scheduling)

– Synchronization costs (e.g. data sharing, inhibited compiler optimization)

5NetProg 6 5

Thread Programming

• Most commonly called Concurrent Programming

• Basic issue: Data can be accessed by multiple threads simultaneously

• Aim: Protecting the data from uncontrolled concurrent access

• Basic solutions:– Thread confinement: don’t share state variables across threads

– Make state variables immutable

– Use synchronization when accessing state variables

• Thread safety: correct program operation (conforms with the specification)

Image source: http://blog.takipi.com/java-thread-magic-tricks/

6NetProg 6 6

Threads and Communications

• Rationale– Time lag between starting to listen to input and data actually

arriving

– Blocking while waiting for input suspends a whole (single threaded) program

• Maintaining control while waiting for input– Option 1: Synchronous communication

• Reader loops asking if data has arrived (e.g. available() )

– Option 2: Asynchronous communication• Callback: create a function to be invoked when data has arrived,

and register the function with the operating system

• Using multiple threads – Allows the blocking of one thread while other threads are running

– In general, threads of a task can execute at different speeds

7NetProg 6 7

Thread Lifecycle

• Thread attributes– ID, Name, Priority,

State

• Enum Thread.State

– NEW: the thread has not yet started

– RUNNABLE: thread executing in the JVM

– BLOCKED: waiting for the availability of an event or a resource

– WAITING: waiting indefinitely for another thread to perform a particular action

– TIMED_WAITING: similar to WAITING but time is limited

– TERMINATED

Image source: http://www.c-jump.com/bcc/c257c/Week13/Week13.html

8NetProg 6 8

Main Thread Methods

Getting information about a thread

• currentThread() Returns a reference to the current thread

• getId() getName() getPriority() getState() return the ID, name, priority and state of the current thread

• toString() returns a string representation of the current thread

Setting thread parameters• setName() setPriority()

• setDaemon(boolean on) marks this thread as daemon or user thread

Execution control

• start() the thread begins execution, the JVM calls the run method of this thread

• run() the Runnable object’s run method is called

• sleep(long millisec) puts the current thread to sleep

• yield() indicates that the current thread is willing to yield its current use of a processor

9NetProg 6 9

Multiple Threads -Code Example

public class Calculator implements Runnable {private int number;

public Calculator(int number) {this.number = number;

}

public void run() {for (int i = 1; i <= 10; i++) {

System.out.printf("%s: %d * %d = %d\n", Thread.currentThread().getName(), number, i, i * number);

}}

}

class Main {public static void main(String[] args) {

for (int i = 1; i <= 10; i++) {Calculator calculator = new Calculator(i);Thread thread = new Thread(calculator);thread.start();

}}

}

10NetProg 6 10

Code Example - Thread States

Main : Status of Thread 0 : NEW

Main : Status of Thread 1 : NEW

Main : Status of Thread 2 : NEW

Main : Status of Thread 3 : NEW

Main : Status of Thread 4 : NEW

Main : Status of Thread 5 : NEW

Main : Status of Thread 6 : NEW

Main : Status of Thread 7 : NEW

Main : Status of Thread 8 : NEW

Main : Status of Thread 9 : NEW

Main : Id 9 - Thread 0

Main : Priority: 10

Main : Old State: NEW

Main : New State: RUNNABLE

Main : ************************************

Main : Id 10 - Thread 1

Main : Priority: 1

Main : Old State: NEW

Main : New State: BLOCKED

Main : ************************************

Main : Id 18 - Thread 9

Main : Priority: 1

Main : Old State: BLOCKED

Main : New State: RUNNABLE

Main : ************************************

Main : Id 18 - Thread 9

Main : Priority: 1

Main : Old State: RUNNABLE

Main : New State: TERMINATED

Main : ************************************

Main : Id 16 - Thread 7

Main : Priority: 1

Main : Old State: BLOCKED

Main : New State: RUNNABLE

Main : ************************************

Main : Id 16 - Thread 7

Main : Priority: 1

Main : Old State: RUNNABLE

Main : New State: TERMINATED

Main : ************************************

Code to Print the Thread Statesimport java.io.*;

import java.lang.*;

public class Calculator_info implements Runnable {

private int number;

public Calculator_info(int number) {

this.number = number;

}

public void run() {

for (int i = 1; i <= 10; i++) {

System.out.printf("%s: %d * %d = %d\n",

Thread.currentThread().getName(), number, i, i * number);

}

}

}

class Main_1 {

public static void main(String[] args) {

Thread threads[]=new Thread[10];

Thread.State status[]=new Thread.State[10];

for (int i = 0; i < 10; i++) {

threads[i]=new Thread(new Calculator_info(i));

if ((i%2)==0){

threads[i].setPriority(

Thread.MAX_PRIORITY);

} else {

threads[i].setPriority(

Thread.MIN_PRIORITY);

}

threads[i].setName("Thread "+i);

}

1/2

try {FileWriter file = new FileWriter("log.txt");PrintWriter pw = new PrintWriter(file);for (int i=0; i<10; i++) {

pw.println("Main : Status of Thread " + i + " : " +threads[i].getState());

status[i] = threads[i].getState();}

for (int i=0; i<10; i++){threads[i].start();

}boolean finish=false;while (!finish) {

for (int i=0; i<10; i++){if (threads[i].getState()!=status[i]) {

writeThreadInfo(pw,threads[i],status[i]);status[i]=threads[i].getState();

}}finish=true;for (int i=0; i<10; i++){

finish=finish &&

(threads[i].getState()==java.lang.Thread.State.TERMINATED);}

}pw.close();

} catch(IOException e){}}private static void writeThreadInfo(PrintWriter pw,

Thread thread, java.lang.Thread.State state) {pw.printf("Main : Id %d - %s\n",

thread.getId(),thread.getName());pw.printf("Main : Priority: %d\n",thread.getPriority());pw.printf("Main : Old State: %s\n",state);pw.printf("Main : New State: %s\n",thread.getState());pw.printf("Main : ************************************\n");

}}

2/2

NetProg 6 11

12NetProg 6 12

Returning Information from a

Thread (1)

• The run() and start() methods do not return anything

• Solution: Using accessor (getter) methods

Steps

– Store the result in a field private to the thread

– Invoke the getter method

• Key point: The thread’s run method has to finish with the data before the accessor method is invoked

13NetProg 6 13

Returning Information from a

Thread (2)• There is no guarantee that one thread will be

faster/slower than another– If you call the getter method too early, the result may not be

ready

• Polling– The getter method returns a flag value (or throws an exception) if

the result is not ready yet

– Problem: inefficient, repeatedly calls the getter method• Even bigger problem: The main program usually has higher priority

and may not allow the thread to run at all

• Callbacks– When the thread finishes, it invokes a method in the main class

• The last step in the run method is invoking a method in the main program with the result

Main program Thread

Start the

thread

Callback

14NetProg 6 14

Callback Example– Code Excerptpublic class CallbackDigest implements Runnable {

private String filename;public CallbackDigest(String filename) {

this.filename = filename;}@Overridepublic void run() {

try {// Calculate the digestbyte[] digest = sha.digest();CallbackDigestUserInterface.receiveDigest(digest, filename);

} catch (IOException ex) {System.err.println(ex);

} catch (NoSuchAlgorithmException ex) {System.err.println(ex);

}}

}

public class CallbackDigestUserInterface {

public static void receiveDigest(byte[] digest, String name) {StringBuilder result = new StringBuilder(name);result.append(": ");result.append(DatatypeConverter.printHexBinary(digest));System.out.println(result);

}public static void main(String[] args) {

for (String filename : args) {CallbackDigest cb = new CallbackDigest(filename);Thread t = new Thread(cb);t.start();

}}

}

Thread

Main program

Callback

For the full example, see the textbook Java Network Programming

15NetProg 6 15

Thread Cooperation Issues

• Thread interferenceIf the following code is accessed by

two threads at the same time, the value of c will depend on the interleaving of the two threads

class Counter {private int c = 0;

public void increment() {c = c + 1;

}

public void decrement() {c = c -1 ;

}

public int value() {return c;

}}

• Memory consistency errorsDifferent threads have different views

of the same data

Example: Lost update

• Thread 1 reads c

• Thread 2 reads c

• Thread 1 increments the retrieved value (result is 1)

• Thread 2 decrements the retrieved value (result is -1)

• Thread 1 stores its value c = 1

• Thread 2 stores its value c = -1

Thread_1’s result has been lost

16NetProg 6 16

Race Conditions

• Definition: The correctness of a computation depends on the timing or interleaving of multiple threads

• Example: Lazy initialization– Initialization of a variable is often postponed until the variable is

used

– If two threads are using the same variable (e.g. a counter), multiple objects can be created instead one – each thread may create an object

• Java provides several methods to avoid race conditions– Synchronized execution

– Using the Volatile keyword

– Locks

– Atomic variables

We look at some of them in this lecture

17NetProg 6 17

Thread Safety

• Levels: thread safe, conditionally safe, not thread safe

• Thread-safe objects– Immutable objects by default

• E.g. read-only and final variables

– Local variables

• Volatile keyword– Guarantees visibility across threads

public volatile int counter = 0;

• Data is always read from memory, not from CPU cache

• The reading and writing instructions of volatile data cannot be reordered by the JVM (e.g. for performance reasons)

• More expensive read and write operations

• Need caution– Static variables (need a lot of caution!)

Code can be executed and shared in multithread environment and will behave as expected (no race conditions)

18NetProg 6 18

Resource Sharing Issues

• The scheduling of threads is unpredictable

• If a shared resource is used by many simultaneously, the result can be confusingE.g. lines (or even items) from different threads can get mixed up in

a printout

• Exclusive access needs to be granted to certain resources (e.g. printers), so that no other thread can jump in

Image source: http://blog.takipi.com/5-things-you-didnt-know-about-synchronization-in-java-and-scala/

19NetProg 6 19

Synchronization

• You can mark a group of statements to be executed without interruption

• It is called synchronization, and it works by locking the object for exclusive use

– Synchronization works only in the same JVM

• Synchronized methodpublic synchronized void increment() {

c = c + 1;}

The method has to complete before another thread can access c . Thread_1’s update will not be lost here

• Synchronized blockpublic void increment() {synchronized(this){

c = c + 1;}

}

• Unsynchronized threads’ operation sequences– are not affected

– have to happen either before or after the synchronized operations take place

20NetProg 6 20

Deadlocks

• If two threads want to access the same resources, deadlock can occur.E.g. Thread 1 has got hold of

B and wants to access A, while Thread 2 has got A and wants to access B.

• Deadlocks – can occur intermittently,

even between the same threads

– usually depend on timing

– can be hard to detect

T1

A

B

Synchronized

on B

T2

Wants to

access A

Wants to

access B

Synchronized

on A

21

Using Synchronization

• Synchronization and locks– Synchronizing a method locks the method

• Static methods lock the class

– Synchronizing a block needs an object to lock• It can be an arbitrary object not used for anything else

E.g. synchronized(this){}

• Synchronization should be used sparingly– It reduces performance

– It can result in a deadlock

• Synchronize only at the lowest level and only the code that really needs it

• To ensure that all threads see the most up-to-date values, the reading and writing threads must synchronize on a common lock

22

Secure Sharing of Objects

• Thread Confinement (no sharing)– Ad-hoc approach: leaves it to the implementation

– Thread-local usage: all variables can be accessed through local variables

– ThreadLocal : Each thread has its own, independently initialized copy of the variable. They are typically private static fields

• Safe publication (sharing)– Synchronized access in both the publishing and the

consuming thread

– Reference to the object and the object’s state must be made visible to other threads at the same time

23NetProg 6 23

Thread Scheduling (1)

• Priorities

– A thread with higher priority gets preference when executed

– A thread’s initial priority is the same as that of its creator

thread

public static final int MIN_PRIORITY

public static final int NORM_PRIORITY

public static final int MAX_PRIORITY

– Interpretation of thread priorities varies between systems

– Thread priority may not indicate share of CPU

Image source: http://www.javamex.com/tutorials/threads/priority_what.shtml

24NetProg 6 24

Thread Scheduling (2)

• Preemption– A running lower priority thread can be interrupted when a higher priority

thread wants to run

• Starvation– A thread does not get (enough) CPU time

– Operating systems usually manipulate thread priorities to avoid starvation

• Changing priorities from the application – It is a hint to the system

– The effect is hard to predict (it depends on the whole system - “OS knows best”)

Image source: http://blog.takipi.com/java-thread-magic-tricks/

25NetProg 6 25

Giving up Control• Blocking

– Waiting for in I/O operation to complete

– Executing a synchronized block

• yield()

– Indicates to the JVM that another thread can run

– The JVM may ignore this hint• The call has minimal effect if no need to yield

• wait(long timeout)

– Waits up to timeout or until another thread sends a notify() signal

– Keeps all its resources (others have to wait for those resources)

• sleep(long millisec)

– Forces the thread to pause, regardless of any threads waiting or not

– The sleeping time may be

• longer, if the JVM is busy doing other things

• shorter if an event or another thread wakes it up (e.g. by sending an interrupt)

– The thread still keeps all its resources

– Avoid using it

• in a synchronized block – can cause a deadlock or long wait

• to wait for an event in another thread – lazy solution, use wait() and notify() instead

26NetProg 6 26

Stopping a Thread

• Once a thread has started, nothing can (safely) stop it, except the thread itself. At most, the thread can be asked to stop itself (by getting interrupted). – An interrupted thread may not immediately stop what it is doing.

Threads may even ignore an interruption request (but that may compromise responsiveness).

• Stopping a thread is a two-step procedure– Design the thread to act on interruption

– Interrupt the thread. It means sending a stop signal to the thread

• interrupt() interrupt this thread

• isInterrupted() tests if this thread has been interrupted

• join() waits for this thread to die

27NetProg 6 27

Interrupting a Thread

• Cooperative mechanism– A signal is delivered to the thread

– The thread stops at the next available opportunity

• A thread can check for interruption regularly– The isInterrupted() method will return true if

interrupted (it leaves the interrupted status unchanged)

– If the thread is in a blocking method, it may take time until it can perform the check

– Blocking methods that support interruption usually throw an exception (InterruptedException)

28

Interruption Code Excerpt (1)

• Thread to be stoppedpublic class myTask extends Thread{

public void run() {

// Do something here

if (isInterrupted()) { // Testing if the thread has been interrupted

// The interrupted status of the thread is unaffectedSystem.out.printf("Interrupted");

return;

}

// Continue normally

}

}

• Main classpublic class Main {

public static void main(String[] args) {

Thread task=new myTask();

task.start();

Thread.sleep(5000); // Do something here

task.interrupt();

...

29

Interruption Code Excerpt (2)

Propagating interruption– Thread to be stopped

public class myTask extends Thread{

public void run() {

try{subTask();

} catch (InterruptedException e) {

System.out.printf("Interrupted“,

Thread.currentThread().getName());

return;

}

// Continue normally

...

private void subTask() throws InterruptedException {

// Do something here

if (Thread.interrupted()) { // Testing if the thread has been interrupted

// The interrupted status of the thread is clearedthrow new InterruptedException();

}

...

– Main classSame as on the previous slide

30NetProg 6 30

Finishing a Thread

• Method 1: join(long milliseconds)

– The invoking thread blocks and waits for another thread (whose method is invoked) to finish

– Can be used for getting the results from another thread

– It is a final method (you cannot override it)

• Method 2: Return from the run() method

– Often used in networking applications

31

Code Excerpt

public class Main {

public static void main(String[] args) {

Thread thread1 = new Thread(myType1,“Type 1");

Thread thread2 = new Thread(myType2,“Type 2");

thread1.start();

thread2.start();

try {

thread1.join();

thread2.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

...

32NetProg 6 32

Reentrancy

• Reentrant code: can be interrupted in the middle of execution and safely re-entered before the previous invocation completes

• Similar to thread safety, but not the same– Reentrant code can achieve thread safety (by observing the respective

rules)

– Thread safe code is not necessarily reentrant

– They still use similar (but not the same) tools (e.g. locks)

• Rules– Reentrant code may not

• use any static or global non-constant data

• call non-reentrant programs, methods

• modify itself

• Examples for reentrant code– Any recursive function

– Interrupt handling

33NetProg 6 33

Thread Groups

• Connect several threads together

• Can be used for handling multiple threads jointly

• You can – list active group members (enumerate() list())

– set limits for them (setMaxPriority())

• Some methods are similar to Thread methods, (e.g. interrupt() setDaemon()) but many are missing (e.g. start() sleep())

• Normally, a thread is in the same group as the main thread of the application

• Example: use in communication applications– You want to stop input and output communication

simultaneously