Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 4 Threads 1. 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) –

Similar presentations


Presentation on theme: "Chapter 4 Threads 1. 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) –"— Presentation transcript:

1 Chapter 4 Threads 1

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 2

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 3

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. 4

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 5

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. 6

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 7

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

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 9

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. 10

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 11

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 12

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 13

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 14

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 15

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. 16

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. 17

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 18

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 19

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 20

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 21

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 22

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 23

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 24

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 25

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 26

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 27

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 28

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 29

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 30

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. 31

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. 32

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 33

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 34

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 35

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 36

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 37

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 38

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 39

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 40

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 41

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) 42

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 43

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 44

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 45

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. 46

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… 47

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 48

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 49

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 50

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 51

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 52

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 53

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 54

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 55

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 56

57 The example code follows Pay particular attention to how a thread is created and started Incidentally note the use of join() 57

58 class MutableInteger { private int value; public int get() { return value; } public void set(int sum) { this.value = sum; } 58

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); } 59

60 public class Driver { public static void main(String[] args) { if (args.length != 1) { System.err.println("Usage Driver "); 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()); } 60

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 61

62 List of Java Thread States New Runnable Blocked Waiting Timed Waiting Terminated 62

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

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 64

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) 65

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 66

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 67

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. 68

69 A Diagram of Thread States and Example Transitional Conditions 69

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. 70

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 71

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 72

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. 73

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 74

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 75

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 76

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

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 78

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() 79

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. 80

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(); } 81

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); } 82

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(); } 83

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; } 84

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; } 85

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; } 86

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. 87

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. 88

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 89

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. 90

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 91

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 92

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 93

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 94

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. 95

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(); 96

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 97

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. 98

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) } 99

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(); } 100

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 101

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 102

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? 103

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 104

105 Asynchronous – These are signals generated by events external to the running process. – Examples are the expiration of a timer or pressing CTRL+C 105

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 106

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 107

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 108

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 109

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 110

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 111

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 112

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 113

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 114

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 115

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 116

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. 117

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 118

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) 119

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 120

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 121

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. 122

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 123

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 124

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 125

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 126

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. 127

128 4.6 Operating System Examples Skip 128

129 The End 129


Download ppt "Chapter 4 Threads 1. 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) –"

Similar presentations


Ads by Google