chapter 4 threads

129
Chapter 4 Threads 1

Upload: weldon

Post on 24-Feb-2016

35 views

Category:

Documents


0 download

DESCRIPTION

Chapter 4 Threads. 4.1 Overview. This is what a thread has of its own: A thread id A program counter A register set (set of register values) A stack The stack contains local variables Therefore, at run time, the value of each variable in shared code can differ among threads. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Chapter 4  Threads

1

Chapter 4 Threads

Page 2: Chapter 4  Threads

2

4.1 Overview

• This is what a thread has of its own:–A thread id–A program counter–A register set (set of register values)–A stack• The stack contains local variables• Therefore, at run time, the value of each variable in

shared code can differ among threads

Page 3: Chapter 4  Threads

3

• This is what it shares with other threads belonging to the same process:–A code section–A data section• The data section contains global variables• Therefore, at run time, each thread has access to a

common set of global variable values

–Other resources, such as open files

Page 4: Chapter 4  Threads

4

• A traditional process with only one thread of control may be known as a heavyweight process

• In a system that supports multi-threaded execution of common code, the threads may be known as lightweight processes.

Page 5: Chapter 4  Threads

5

Motivation

• Multi-threading is a way of avoiding the overhead of creating full new (heavyweight) processes

• It is a way of allowing multi-tasking within a single (heavyweight) process

Page 6: Chapter 4  Threads

6

Examples

• A word processor might support concurrent text entry and spell checking by having each run as a separate thread.

• A Web server may receive many requests for service—all essentially the same.

• Rather than creating a separate process for each, it may spawn threads of the same request-handling code.

• O/S kernels may also be multi-threaded. • Solaris does interrupt handling with threads.

Page 7: Chapter 4  Threads

7

Benefits

• By definition, threads allow resource sharing• Threads decrease the overhead of process creation

—the creation of threads is less computationally demanding

• Threads introduce a form of concurrency, promoting efficient use of resources and system responsiveness

• Threads may be used in multi-processing, where separate threads run on each processor, rather than separate processes

Page 8: Chapter 4  Threads

8

• The book gives this list of benefits:• 1. Responsiveness• 2. Resource sharing• 3. Economy• 4. Scalability

Page 9: Chapter 4  Threads

9

Multi-Core Programming

• On a multi-core chip, each core appears as a separate processor to the O/S

• Multi-threading can be applied directly in a multi-core environment

• Each thread can run in parallel, (simultaneously, not concurrently) on one of the cores

Page 10: Chapter 4  Threads

10

Challenges of Parallel Processing

• This sounds nice, but the challenge of parallel programming has always been how to break the problem into pieces and put the partial solutions together at the end.

• In order to get the best use out of multiple cores, both O/S code and application code have to be (re-) written to take advantage of parallelization.

Page 11: Chapter 4  Threads

11

• The book defines the challenge in greater detail under five points:

• 1. Dividing activities (as mentioned already)• 2. Balance (part of dividing): Splitting the

problem evenly so each part is significant enough to have its own thread/core

• 3. Data splitting: The point here is whether data can or needs to be split among threads

Page 12: Chapter 4  Threads

12

• 4. Data dependency– This is the devilish part of data.– You may be able to split the code, but the code

shares data– This means that a correct solution will require

synchronization on the data

Page 13: Chapter 4  Threads

13

• 5. Testing and debugging– This is a nightmare with parallel code– We will get a taste of how hard this problem must

be when we consider debugging of synchronized (or incorrectly synchronized) code

Page 14: Chapter 4  Threads

14

• The book ends the section on multiple cores with observations along these lines:– In effect, parallel programming is becoming a

common, rather than a rare challenge– In order for software to make effective use of

multiple cores new approaches to code design may be needed in the future

– Parallel programming techniques do exist—but they are currently a specialty that is not widely known or taught

Page 15: Chapter 4  Threads

15

4.2 Multi-threading Models

• User and kernel threads• Threads can be supported at the user level in

the layered diagram of system software• Threads can also be supported directly in the

kernel of the O/S

Page 16: Chapter 4  Threads

16

• Wherever they are implemented, context switching between threads is necessary.

• This is less expensive than switching between processes.

• If user level threads are supported which differ from kernel level threads, there has to be a mapping between the user level threads and the kernel level threads or processes.

Page 17: Chapter 4  Threads

17

• In other words, user level threads are assigned to kernel level threads.

• The kernel level threads become analogous with a processor, and user level threads are “scheduled” to run on them.

Page 18: Chapter 4  Threads

18

The Many-to-One Model

• Many user level threads share (are concurrently executed by) a single kernel level thread

• Solaris Green threads and GNU portable threads implement this model

Page 19: Chapter 4  Threads

19

Characteristics of This Model

• Efficiency: Thread management is handled in user space

• Blocking: Any one blocking call by a user thread will cause all of the threads to block

• Parallel processing: This model is not applicable in this environment. – There is only one underlying kernel thread– That thread can only use one processor

Page 20: Chapter 4  Threads

20

The One-to-One Model

• Each user level thread is mapped to a single kernel level thread

• Linux and Windows 95/98/NT/2000/XP implement this model

Page 21: Chapter 4  Threads

21

Characteristics of This Model

• Efficiency: Each user thread has the overhead of kernel thread creation. – Most systems put an upper bound on the number

of threads allowed• Blocking: One thread can’t block the others• Parallel processing: This model fits the

requirements– Each kernel thread = one user thread can run on a

separate processor

Page 22: Chapter 4  Threads

22

The Many-to-Many Model

• Multiple user level threads map to a set, possibly smaller, of kernel threads

• The system interactively maps user to kernel threads when scheduling

• This is more flexible than the other models, but also more complex

Page 23: Chapter 4  Threads

23

• The term “two level model” describes a system with m-to-n mapping plus the ability to map one user thread to a single kernel thread

• The two level model is the most general model

• IRIX, HP-UX, and Tru64 Unix implement the two level model

Page 24: Chapter 4  Threads

24

Characteristics of This Model

• Efficiency: The system can allocate as many kernel threads as is practical or optimal

• Blocking: There is no blocking• Parallel processing: This supports parallelizing

a number of kernel threads up to the number of processors– Each kernel thread can run on a separate

processor

Page 25: Chapter 4  Threads

25

4.3 Thread Libraries

• A thread library provides an API for creating and using threads

• There are two main non-virtual machine thread libraries– The POSIX (Unix) Pthread library supports either

user or kernel threads– The Win32 threads library supports kernel threads

• The details of these subsections will not be covered

Page 26: Chapter 4  Threads

26

• Linux also supports the thread concept, although it uses different terminology

• Java threads are implemented on top of whatever O/S thread environment the JVM is installed on

Page 27: Chapter 4  Threads

27

4.4 Java Threads

• These overheads will try and follow the O/S book’s examples

• If you find that the presentation of the mechanics of threading is sketchy, I recommend the following:

• Go to the CS 202 Web page• Find Unit 29 there, which is not covered in CS 202

anymore• Take a look at the overheads/note file/example

programs to get a clearer introduction to threads, based on building blocks that you covered in CS 202

Page 28: Chapter 4  Threads

28

• Threads are fundamental to the Java model• A single program runs as a single thread if it

doesn’t explicitly create threads• Syntax exists to create separate threads in a

program

Page 29: Chapter 4  Threads

29

• The idea is that if the machine is virtual, why not support virtual processes?

• This allows the use of multi-programming/multi-tasking when writing code at the user level

Page 30: Chapter 4  Threads

30

• Java threads don’t fit the user level vs. kernel level thread API library distinction very well

• In Java, threads are supported in the Java language API

• They are actually implemented in the JVM, which relies on the underlying system

Page 31: Chapter 4  Threads

31

• One of the biggest challenges to the use of Java threads is understanding that their behavior and scheduling depends in part on the behavior and scheduling of threads as defined in the underlying system.

Page 32: Chapter 4  Threads

32

• Threaded Java code may be formally correct, meaning that it is correctly synchronized, but its run-time behavior may differ in different environments.

• This is due to the different handling of system level threads in those environments, which the JVM threading mechanism is built on top of.

Page 33: Chapter 4  Threads

33

Java Thread Creation

• This section is mostly about syntax• Learning about the syntax is important if you

want to use Java threads yourself• It’s also helpful because it makes it possible to

consider example programs provided by the authors

• What threads are may become clearer if you can understand what an actual threaded program is and how it works

Page 34: Chapter 4  Threads

34

First Approach to Writing a Threaded Application

• Write a class that extends the Thread class in the Java API

• Override the run() method in that class• It is the run() method which contains the

program logic which is to be threaded

Page 35: Chapter 4  Threads

35

• In a program, construct an instance of the class that extends the Thread class

• Call the start() method on that object• The start() method allocates memory and

initializes a new thread in the JVM

Page 36: Chapter 4  Threads

36

• The start() method contains a call to the object’s run() method

• The user program shouldn’t call the run() method directly because the initialization and allocation steps would be missed

• This first approach works fine in simple cases

Page 37: Chapter 4  Threads

37

• Observe that since a class can only extend one other class, if your class extends the Thread class, it can’t be a subclass of any other class

• For example, an applet is created by extending the JApplet class.

• This approach won’t allow you to make a threaded applet

Page 38: Chapter 4  Threads

38

• This suggests that there has to be an interface based solution to the problem

• That will be the second approach• There is an explanation for why the simple

approach is not the best approach conceptually

Page 39: Chapter 4  Threads

39

• Ideally, when defining one class to be a subclass of another, the subclass should be a “kind of” the superclass

• Extending the Thread class in order to override the run() method doesn’t make a new kind of Thread class

• What it does is create a class which can make use of threading

Page 40: Chapter 4  Threads

40

The Second Approach to Writing a Threaded Application

• Write a class that implements the Runnable interface

• That interface specifies a run() method and nothing more

• Implement a run() method in your class

Page 41: Chapter 4  Threads

41

• You can then create a thread based on your class using this mechanism:

• Construct an instance of your class• Construct an instance of the Thread class, using the

constructor which takes as a parameter a reference to an object which implements the Runnable interface.

• Pass an object of your class as the parameter.• Call the start() method on this instance of the Thread

class

Page 42: Chapter 4  Threads

42

• Think back to the first solution for a moment.• For what it’s worth, note that in the Java API, the

Thread class implements the Runnable interface• The Thread class has a run() method, and therefore

meets the requirements for being Runnable• In a sense, the first solution was a special case of the

second solution• The key requirement for something to be able to run

independently is that it implement the Runnable interface (the run() method)

Page 43: Chapter 4  Threads

43

• When using the second approach, the Thread class constructor takes the runnable object and “wraps” it into a thread

• There are no special requirements for the constructors of the runnable class itself.

• A default constructor may work; • Constructors that take parameters may be

needed. • It’s application dependent

Page 44: Chapter 4  Threads

44

An Example Threaded Program

• The book’s example program is based on the idea of summing the first n integers

• It will be covered in this way– By explaining the general idea behind the

implementation– By pointing out some of the syntactical details– And then by looking at the code overall

Page 45: Chapter 4  Threads

45

• Recall the previous example on producers and consumers in chapter 3

• The authors wanted to illustrate a concept using Java code

• However, in order to do so completely correctly, it would have been necessary to use syntax that hadn’t been explained yet

Page 46: Chapter 4  Threads

46

• Therefore, the example illustrated the general idea but with several key pieces missing

• At the same time, the authors did feel compelled to use the keyword “volatile” in their code

• If the code wasn’t correctly threaded or synchronized anyway, it wasn’t clear why that particular detail did have to be included.

Page 47: Chapter 4  Threads

47

• This example has similar problems.• It still doesn’t do everything correctly• But it does include other stuff which is

advanced and, from the point of view of understanding the concept they’re trying to illustrate, extraneous…

Page 48: Chapter 4  Threads

48

• The point now is really just to see how threads can be made and used

• The example they’ve chosen, if it were really amenable to a threaded solution, would require synchronization

Page 49: Chapter 4  Threads

49

• They aren’t ready to tackle synchronization yet, so instead, they introduce the syntax for making one thread wait on another

• In order to understand the example, it will be necessary to go through the thread waiting syntax, as well as the thread creation and usage syntax

Page 50: Chapter 4  Threads

50

• The purpose of the program is to find the sum of the integers less than or equal to some given upper limit

• The overall structure of the program consists of a driver, which does input and output, and a run() method in another class which does the summing

• The driver and the run() method run as separate threads

Page 51: Chapter 4  Threads

51

• Because the run() method in the Runnable interface specification is void, it is not possible for it to return a computed value

• This can be overcome by passing a reference to an object where the result of the computation is stored in that object

Page 52: Chapter 4  Threads

52

• The authors choose to name the class which holds the result of the computation MutableInteger

• This name indicates that it would not be possible to pass an instance of the system supplied Integer class, since objects of that class are immutable

Page 53: Chapter 4  Threads

53

• Although, in theory, a principal advantage of threading is that the threads run concurrently, this introduces the potential for synchronization problems

• These problems have not been addressed yet, so the authors avoid them in this way:

• They use syntax which requires that after starting the summation thread, the thread of the driver has to wait for it to complete

Page 54: Chapter 4  Threads

54

• From the point of view of clarity of the example, this has two disadvantages:– It’s necessary to introduce the syntax for making one

thread wait on another– Conceptually, it results in a threaded program whose

behavior could more easily have been accomplished by non-threaded code

• In any case, the example does result in code which is threaded and does not have lurking synchronization issues

Page 55: Chapter 4  Threads

55

• The name of the method that causes one thread to depend on another is join()

• If the main() method (thread) constructs and starts another thread, a call to join() on that other thread will cause the main() method to depend on it

• The call to join() has to occur in a try block because it can throw an exception

Page 56: Chapter 4  Threads

56

• The authors introduce one more thread concept which isn’t directly relevant to the example

• There are daemon threads and non-daemon threads

• For all practical purposes, you can consider user threads to be non-daemon threads

• There is no need to worry about daemon threads or the syntax for making a thread a daemon thread

Page 57: Chapter 4  Threads

57

• The example code follows• Pay particular attention to how a thread is

created and started• Incidentally note the use of join()

Page 58: Chapter 4  Threads

58

• class MutableInteger• {• private int value;

• public int get() {• return value;• }

• public void set(int sum) {• this.value = sum;• }• }

Page 59: Chapter 4  Threads

59

• class Summation implements Runnable• {• private int upper;• private MutableInteger sumValue;

• public Summation(int upper, MutableInteger sumValue) {• if (upper < 0)• throw new IllegalArgumentException();

• this.upper = upper;• this.sumValue = sumValue;• }

• public void run() {• int sum = 0;

• for (int i = 0; i <= upper; i++)• sum += i;

• sumValue.set(sum);• }• }

Page 60: Chapter 4  Threads

60

• public class Driver• {• public static void main(String[] args) {• if (args.length != 1) {• System.err.println("Usage Driver <integer>");• System.exit(0);• }

• MutableInteger sumObject = new MutableInteger();• int upper = Integer.parseInt(args[0]);•• Thread worker = new Thread(new Summation(upper, sumObject));• worker.start();• try {• worker.join();• } catch (InterruptedException ie) { }• System.out.println("The value of " + upper + " is " +

sumObject.get());• }• }

Page 61: Chapter 4  Threads

61

Java Thread States

• Note the parallel between threads and processes– Java threads are like processes at the user level– Processes have states– Threads also have a life cycle that can be

described with states

Page 62: Chapter 4  Threads

62

List of Java Thread States

• New• Runnable• Blocked• Waiting• Timed Waiting• Terminated

Page 63: Chapter 4  Threads

63

New

• Results from the call to construct a new() instance of a Thread

Page 64: Chapter 4  Threads

64

Runnable

• Calling start() allocates memory for a thread object

• When run() is called, a thread enters the runnable state

• Java doesn’t distinguish between runnable and running.

• A running thread is in the runnable state. • Other threads may be in the runnable state but

not currently running

Page 65: Chapter 4  Threads

65

Blocked

• This happens if a thread issues a command that causes blocking

• Previously, the classic example that would be given was I/O

• Another example that used to be given was a call to such a method as sleep()

• The book currently gives as the canonical example waiting to acquire a lock (a synchronization concept)

Page 66: Chapter 4  Threads

66

Waiting

• This means waiting for an action by another thread

• If thread 1 calls join() on thread 2, thread 1 will wait for thread 2 to terminate before continuing

Page 67: Chapter 4  Threads

67

Timed Waiting

• This is similar to waiting, but with a maximum wait time telling when the wait expires

• join() can be called with a time parameter• This prevents indefinite waiting in case thread

2 doesn’t terminate in a timely fashion• It is not clear whether sleep(), for example,

now falls into this category

Page 68: Chapter 4  Threads

68

Terminated

• A thread enters the terminated state when execution reaches the end of the run() method

• Note the difference between this and garbage collection when there is no longer a reference to a thread object

• In theory, a thread can terminate successfully and then be run() again by another call somewhere in the running code.

Page 69: Chapter 4  Threads

69

A Diagram of Thread States and Example Transitional Conditions

Page 70: Chapter 4  Threads

70

The JVM and the Host O/S

• The states given above are thread states as they exist in the JVM

• These states do not necessarily agree with any particular lightweight or heavyweight system thread which the Java thread is running on

• Note that it may be difficult or impossible for the programmer/user to determine the relationship between a Java thread and the native environment thread or process that it is running on.

Page 71: Chapter 4  Threads

71

• The Java specification does not say how Java threads are to be mapped to system threads

• Thread mapping is up to whoever does the implementation for Java for a given environment (note that in theory there could be more than one implementation even for the same environment)

• Windows XP, for example, does one-to-one mapping• Unix type systems may do many-to-one or many-to-

many mapping

Page 72: Chapter 4  Threads

72

• There are no thread scheduling requirements (other than correctness) in the Java specifications.

• Threaded Java applications can vary in their behavior in different environments

Page 73: Chapter 4  Threads

73

• There are Java API methods that make it possible to check the status of a Java thread:– isAlive(): returns true if the thread has not yet

terminated– getState(): returns one of the Java thread states

listed above.

Page 74: Chapter 4  Threads

74

A Multi-threaded Solution to the Producer-Consumer/Mailbox Problem

• This takes the message passing example of the last chapter one step closer to reality

• It uses this code, already given:• The Channel interface• The MessageQueue class. – Remember that this contained an instance of a

vector and implemented an unbounded buffer

Page 75: Chapter 4  Threads

75

• The example program overall contains four other classes

• It makes use of messages that contain dates that are instances of the Java API Date class

• The four classes and their contents are outlined below

Page 76: Chapter 4  Threads

76

• Factory– Create the mailbox– Create the producer thread, passing it a reference

to the mailbox– Create the consumer thread, passing it a reference

to the mailbox– Start both threads

Page 77: Chapter 4  Threads

77

• Producer– Run in a loop– Sleep a while– Create a message– Put it in the mailbox– Print a message saying so

Page 78: Chapter 4  Threads

78

• Consumer– Run in a loop– Sleep a while– Retrieve a message or null if there isn’t one (this is

non-blocking)– Print a message saying so

Page 79: Chapter 4  Threads

79

• The SleepUtilities class– Sets a given sleeping time– Calls the Thread class sleep() method– Note that try/catch blocks are needed for various

calls which are brought together in the code for sleep()

Page 80: Chapter 4  Threads

80

Final Notes on the New Code

• This example is more complete than given in the last chapter.

• It is threaded.• However, it is still not complete. • Once two threads share (a reference to) an object,

there is a concurrency control or synchronization issue.• This code does not deal with that issue explicitly. • The issue will be discussed in detail in a future chapter.

Page 81: Chapter 4  Threads

81

• public interface Channel• {• /**• * Send a message to the channel.• * It is possible that this method may or may not

block.• */• public abstract void send(Object message);• • /**• * Receive a message from the channel• * It is possible that this method may or may not

block.• */• public abstract Object receive();• }

Page 82: Chapter 4  Threads

82

• import java.util.Vector;• • public class MessageQueue implements Channel• {• private Vector queue;

• public MessageQueue() {• queue = new Vector();• }• • /*• * This implements a non-blocking send• */• public void send(Object item) {• queue.addElement(item);• }• • /*• * This implements a non-blocking receive• */• • public Object receive() {• if (queue.size() == 0)• return null;• else • return queue.remove(0);• }• }

Page 83: Chapter 4  Threads

83

• public class Factory • { • public Factory()• {• // first create the message buffer • Channel mailBox = new MessageQueue();• • // now create the producer and consumer threads• Thread producerThread = new Thread(new Producer(mailBox));• Thread consumerThread = new Thread(new Consumer(mailBox));• • producerThread.start();• consumerThread.start(); • }

• public static void main(String args[]) { • Factory server = new Factory();• }• }

Page 84: Chapter 4  Threads

84

• import java.util.*;

• class Producer implements Runnable• {• public Producer(Channel m)• {• mbox = m;• } • • public void run()• {• Date message;• • while (true) { • SleepUtilities.nap(); • message = new Date(); • System.out.println("Producer produced " + message);• // produce an item & enter it into the buffer• mbox.send(message);• }• }• • private Channel mbox;• }

Page 85: Chapter 4  Threads

85

• import java.util.*;

• class Consumer implements Runnable• {• public Consumer(Channel m) { • mbox = m;• }• • public void run() {• Date message;• • while (true)• {• SleepUtilities.nap();

• // consume an item from the buffer• System.out.println("Consumer wants to consume.");• message = (Date)mbox.receive();• if (message != null)• System.out.println("Consumer consumed " + message);• }• }• • private Channel mbox;• }

Page 86: Chapter 4  Threads

86

• /**• * Utilities for causing a thread to sleep.• * Note, we should be handling interrupted exceptions• * but choose not to do so for code clarity.• */

• public class SleepUtilities• {• /**• * Nap between zero and NAP_TIME seconds.• */• public static void nap() {• nap(NAP_TIME);• }

• /**• * Nap between zero and duration seconds.• */• public static void nap(int duration) {• int sleeptime = (int) (duration * Math.random() );• try { Thread.sleep(sleeptime*1000); }• catch (InterruptedException e) {}• }

• private static final int NAP_TIME = 5;• }

Page 87: Chapter 4  Threads

87

4.5 Threading Issues

• What happens when you have threads on top of processes?

• What should the effect of (process) calls like fork() and exec() be, when made in a program that is running multiple threads?

• This is just more “bulleted list” stuff.• In other words, as more different ideas are

presented, the possible relationships between them are points to ponder.

Page 88: Chapter 4  Threads

88

• Q: In a multi-threaded program, if one thread calls exec(), should the whole process, all of the threads, be replaced, or just the calling thread?

• A: exec() typically replaces the whole process• exec() is a process level call, and its effects are

at the process level, not the thread level, even though, by definition, in a threaded program the call has to originate in a thread.

Page 89: Chapter 4  Threads

89

• Q: In a multi-threaded program, if one thread calls fork(), should all of the threads be duplicated, or just the calling thread?

• A: Taking Unix as an example, some versions of that O/S have two different versions of fork()

• One version duplicates all of the threads, the other duplicates just the calling thread

Page 90: Chapter 4  Threads

90

• Which version of fork() to use depends on whether or not you plan on using exec() in the forked code

• It’s more expensive to duplicate all threads rather than just one thread

• If you’re writing code where you’re going to call exec() after fork(), use the fork() that just duplicates the one thread because they’re all going to get wiped out anyway.

Page 91: Chapter 4  Threads

91

• If you’re not going to call exec(), use the fork() that duplicates all of the threads.

• If you’re not replacing the running process, you want duplicates of all of its components

Page 92: Chapter 4  Threads

92

Thread Cancellation

• This term refers to making a call that will terminate a running thread before it has naturally come to the end of run()

• You have one piece of code, or thread, which contains a reference to another thread, the target thread

• The one piece of code can cancel the target thread by making a call on it

Page 93: Chapter 4  Threads

93

Two Models of Cancellation

• Asynchronous cancellation (literally, cancellation without synchronization): – The one thread immediately terminates the target

• Deferred cancellation:– The one thread sets a parameter or makes a call

signaling that the target should be cancelled– The target is coded to periodically check its status

and to terminate itself if it has been signaled to cancel

Page 94: Chapter 4  Threads

94

• Asynchronous cancellation can lead to concurrency problems

• If the target shares resources with another thread or if it holds resources allocated by the system, asynchronous/immediate cancellation may:– Leave the resources in an inconsistent (undesirable)

state– Make it impossible for the system to reclaim the

thread’s resources

Page 95: Chapter 4  Threads

95

• In Java, the stop() call implements asynchronous cancellation.

• Code written in the past may have used it. • It is now deprecated due to these

synchronization problems.

Page 96: Chapter 4  Threads

96

The Logic of Deferred Cancellation

• The target thread checks to see if it has been signaled to terminate

• If so, it runs housekeeping code which leaves resources in a consistent state

• Then it exits• In Java, in the canceling thread, deferred

cancellation is triggered by this call: • targetThread.interrupt();

Page 97: Chapter 4  Threads

97

• In the target code there is a choice between two different calls:

• me.interrupted()• This returns true or false and clears the

interrupted status• me.isInterrupted()• This returns true or false and doesn’t clear the

interrupted status

Page 98: Chapter 4  Threads

98

• Code for an Interrupter class and an InterruptibleThread class follow

• The code for the InterruptibleThread class has been modified slightly from the book’s example

• Note that the InterruptibleThread class implements Runnable rather than extending Thread.

• This means you have to call the static method Thread.currentThread() in order to get a reference to yourself

• This is sort of a “who am I” call.

Page 99: Chapter 4  Threads

99

• public class InterruptibleThread implements Runnable• {• /**• * This thread will continue to run as long• * as it is not interrupted.• */• private boolean keepOnRunning = true;• public void run()• {• while (keepOnRunning)• {• /**• * do some work for awhile• */

• if (Thread.currentThread().isInterrupted())• {• System.out.println("I'm interrupted!");• keepOnRunning = false;• }• }• // clean up and terminate (housekeeping)• }• }

Page 100: Chapter 4  Threads

100

• public class Interrupter• {• public static void main(String[] args)• {• Thread worker = new Thread (new InterruptibleThread());• worker.start(); • // now wait 3 seconds before interrupting it• try• { • Thread.sleep(3000);• }• catch (InterruptedException ie)• {• }• worker.interrupt();• }• }

Page 101: Chapter 4  Threads

101

Another Logical Puzzle Typical of Operating Systems Stemming from this Example

• A blocked thread can’t run, so it can’t check its status

• A thread blocked for I/O, for example, won’t check its status until the I/O finishes

• If it is desirable to interrupt blocked processes in Java, suitable methods can be found in the API under java.nio

• The standard methods in java.io won’t work

Page 102: Chapter 4  Threads

102

Signal Handling

• Like the discussion of fork() and exec(), this section is Unix related

• In Java, you get to understand threading at the user level

• In Unix, it is possible to work directly with processes and system threads

• Interactions that could occur in that environment become a consideration when discussing what threads are and how they work

Page 103: Chapter 4  Threads

103

• In Unix, the occurrence of events is signaled like a software interrupt

• When a signal is received, it has to be handled• The question is, what happens when a multi-

threaded process is signaled? • Which of the threads is signaled?

Page 104: Chapter 4  Threads

104

Synchronous and Asynchronous Signals

• Synchronous – If a running process is the immediate cause of the

signal generation, the signal is sent to that process.

– Examples are division by 0 and illegal memory access

Page 105: Chapter 4  Threads

105

• Asynchronous – These are signals generated by events external to

the running process. – Examples are the expiration of a timer or pressing

CTRL+C

Page 106: Chapter 4  Threads

106

• The four examples of signals given above would cause termination.

• It is coincidental that these commonplace examples lead to termination

• In general this doesn’t have to be the case when handling signals

Page 107: Chapter 4  Threads

107

• Any event may be handled by one of two possible types of handlers– A default signal handler—system code run by the

kernel– A user-defined signal handler may be provided

• In a single-threaded process, signal delivery is clear:

• The signal is delivered to the one process in question

Page 108: Chapter 4  Threads

108

Four Choices for Multi-threaded Signal Handling

• 1. Deliver the signal to the one thread to which it applies (see the concrete example below)

• 2. Deliver the signal to every thread in the process (see the concrete example below)

• 3. Deliver the signal to certain threads in the process

• 4. Deliver the thread to a thread which has been designated to receive all of the signals for the process

Page 109: Chapter 4  Threads

109

Example of 1

• For synchronous threads, it makes sense to deliver the signal to the thread which caused the signal to be generated.

• If one thread of many divided by 0, that thread should be signaled

Page 110: Chapter 4  Threads

110

Example of 2

• CTRL+C in Unix is interpreted to mean “stop the process.”

• Thus, in a multi-threaded application, this should generate a signal to all threads to stop

Page 111: Chapter 4  Threads

111

The General Plan of Action in Unix

• The Unix command kill() is used to send signals.

• Think of kill() as meaning interrupt, not terminate

• Individual threads can be set to block or not block signals of different kinds

Page 112: Chapter 4  Threads

112

• Signals are sent to/received by the first available thread that is not blocking that kind of signal

• Sending a signal to one (appropriate) thread is sufficient since signals only have to be handled once

• Windows doesn’t use signals, but it has a facility that can accomplish the same thing.

• This fact and the details of the facility are not important

Page 113: Chapter 4  Threads

113

Thread Pools

• If a system is trying to run too many processes, performance can suffer

• Process creation can be expensive• One of the motivations for threads was to save

on the expense of full-scale process creation

Page 114: Chapter 4  Threads

114

• The same arguments apply to threads• Running too many threads can affect

performance• In the long run, the expense of thread creation

is also pure overhead cost

Page 115: Chapter 4  Threads

115

• The overall problem is one of continuously creating things, destroying them, and creating new ones again

• A thread pool is a solution to this problem• The idea is to create a collection of threads in

advance• When a task arrives in the system which can be

handled by a thread, one from the pool is assigned to that task

Page 116: Chapter 4  Threads

116

• If no free thread is available, the task has to wait

• When the task is finished, the thread is returned to the pool, not destroyed

• This is both a reasonably simple and reasonably clever idea for managing system resources

• An example of its use is in servicing Web requests

Page 117: Chapter 4  Threads

117

• It would take some effort to come up with a good algorithm to match the thread pool size to the workload on a system at any given time

• The book gives a bunch of details on thread pools.

• This includes the Java syntax for creating thread pools and executing threads in a pool

• None of those details are of importance at this time.

Page 118: Chapter 4  Threads

118

Thread Specific Data

• The default condition for threads is that they share data.

• This is one of the reasons they are advantageous.

• This means that by default, simple threads don’t have data of their own

Page 119: Chapter 4  Threads

119

• It may be desirable for threads to keep track of data items of their own.

• An example might be assigning a thread the id of a task it’s been assigned to do (like when giving a thread in a pool a task)

Page 120: Chapter 4  Threads

120

• It is possible to give threads their own data items using known syntax

• For example, the thread class could be extended with an instance variable added

• Or a class that implements the Runnable interface could have an instance variable and get() and set() methods, and the run() method might affect the value of the variable

Page 121: Chapter 4  Threads

121

• The previous solutions don’t work in the thread pool scenario, where the user doesn’t create the thread that does the task

• Java has a ThreadLocal class that can be used to declare data items that will be distinguished by the system according to which thread is running them/which thread they belong to

Page 122: Chapter 4  Threads

122

• The book gives an example, but it doesn’t show the solution to the pool problem.

• It illustrates the new syntax by solving a problem more easily solved using techniques mentioned earlier

• There is no reason to pursue the details of this example.

Page 123: Chapter 4  Threads

123

Scheduler Activations

• This is a discussion of issues involved in the many-to-many model of mapping user threads to kernel threads

• Here is a layered diagram– User thread– Lightweight process– Kernel threads– Hardware

Page 124: Chapter 4  Threads

124

• The lightweight process is what the threading system presents to the user level thread library

• It can be thought of like a virtual processor that a user level thread can be scheduled on

• Communication between the kernel and user level thread library is done by means of upcalls and upcall handlers

Page 125: Chapter 4  Threads

125

• An upcall is like a signal (or interrupt) to the thread library

• An upcall handler is like an interrupt handler. • In this case it can be thought of as scheduler

code• The kernel sends an upcall when a lightweight

process has become available for a thread to be scheduled on

Page 126: Chapter 4  Threads

126

• At the beginning of a system run, many lightweight processes may be free

• After a system has begun running, the classic cause of an upcall is that a thread which has already been scheduled on a lightweight process has issued a blocking call.

• At that point the thread enters a waiting state and the lightweight process becomes available for scheduling

Page 127: Chapter 4  Threads

127

• I am not going to go into detail on this topic.• The reason is that these are fundamentally

scheduling questions.• Scheduling is the topic of the next chapter.• It doesn’t cover thread scheduling in

particular, but that is the place where all of the details of scheduling that you will need to master are given.

Page 128: Chapter 4  Threads

128

4.6 Operating System Examples

• Skip

Page 129: Chapter 4  Threads

129

The End