Chapter 4.1: Threads. 4.2 Silberschatz, Galvin and Gagne ©2005 Operating System Concepts Threads...

29
Chapter 4.1: Threads Chapter 4.1: Threads
  • date post

    19-Dec-2015
  • Category

    Documents

  • view

    218
  • download

    1

Transcript of Chapter 4.1: Threads. 4.2 Silberschatz, Galvin and Gagne ©2005 Operating System Concepts Threads...

Chapter 4.1: ThreadsChapter 4.1: Threads

4.2 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Threads – Our Chapter 4 OutlineThreads – Our Chapter 4 Outline This chapter addresses multi-threaded computing systems Most modern operating systems provide processes with multiple threads of

control.

We will present a discussion of the principles of threading along with its benefits followed by multi-threading models.

We will then discuss Thread Libraries and in this section, we’ll discuss Pthreads and Java threads. We will also look at some code here.

We will then discuss Threading Issues with related fork() and exec() and clone() system calls, cancelling threads while threads are in execution, the signaling system in Unix, and thread pools.

We will look closely how threads are implemented in Linux

We will not discuss the Win32 API and how it addresses threading in the Windows environment and we will not discuss lightweight processes (LWPs) as this topic is somewhat dated.

This is a very important chapter. There will be assignments presented at the conclusion of the chapter.

4.3 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Overview of ThreadsOverview of Threads

“A thread is a basic unit of CPU utilization;”

This means the CPU is dispatched to execute threads.

Threads are scheduled for CPU cycles; threads are ‘managed.’

Thread within the same process share a code section, data section, and other resources such as open files and signals. (signals discussed later).

Idea behind threads is that the process can perform many different activities at the same time (concurrently, of course, on a single CPU)

In the past, we have processes with a single thread of control, which means processor can perform one task at a time.

Thread management and management of multiple threads of control become serious issues nowadays since most modern desktop and notebook computers have multiple processors (dual core – which is ‘almost’ multiple processors).

So what do we mean by multiple threads of control? Why important?

4.4 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Multiple Threads of ControlMultiple Threads of Control

Most modern applications are developed as a separate process with several threads of control. This means a number of separate ‘tasks’ that are part

of the application can be executed concurrent with other tasks.

A word processor might be echoing keystrokes and yet automatically (another thread) might be undertaking styling formatting or checking and doing automatic correcting “at the same time.”

If these tasks had to be executed sequentially, performance would be unbearable or simply would not be done thus reducing the overall quality of, say, a document.

4.5 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Multiple Threads of ControlMultiple Threads of Control Process Creation. We know that process creation is time

consuming, and a server creates separate processes when a request for service arrives. Way of doing business before we used threads.

So, in order to service a number of perhaps seemingly disjoint tasks concurrently, we need multiple threads which means that we need multiple levels of control!

Solution is to have the server create a single thread that ‘listens’ for new requests for service.

When received, server creates a thread to service the request.

RPCs and Java RMI systems are multi-threaded in that when a server receives a message, the message is serviced by a separate thread, thus providing for concurrent processing.

Extending this thinking, kernels are multi-threaded where different threads perform different operating system tasks as well..

4.6 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Single and Multithreaded ProcessesSingle and Multithreaded Processes

It is important to note, however, that a multi-threaded process shares resources with its siblings and parent process… Much more later.

4.7 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Benefits are ManyBenefits are Many

Responsiveness - Parts of a program can continue running even if parts of it are blocked. Book points out that a multi-threaded web browser could still allow user interaction in one thread while downloading a gif in another thread…

Resource Sharing – pros and cons here. By sharing memory or other resources (files, etc.) the threads share the same address space. (there are issues here…)

Economy – since threads share resources, it is easier to context-switch threads than context-switching processes. This should be clear.

Utilization of MP Architectures – there will be significant increases in performance in a multiprocessor system, where different threads may be running simultaneously (in parallel) on multiple processors.

Of course, there’s never ‘a free lunch,’ as we will see later. (There’s always a cost…; nothing this good comes free. )

4.8 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

User ThreadsUser Threads

We know that we have threads at both user level and kernel levels. User threads are supported above the kernel and are managed

without kernel support. But kernel threads are directly managed by the operating system. Because we have both user threads and kernel threads in the same

context, there must be a relationship between the two. Both kinds of threads are vying for he processor!!!

We have models whereby user threads are related to kernel threads. Many to One Model One to One Model, and the Many to Many Model

4.9 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Thread Models – Many to One ModelThread Models – Many to One Model

Many-to-One Model This model maps multiple user threads to a single kernel thread. Because the management of these user threads is done by the

thread library in user space, it is very efficient. But, unfortunately, because there is only a single kernel thread in

this model, the entire process will block if any thread issues a system call.

Further, since only a single thread can access the kernel at a given instant, multiple threads are not able to run in parallel on multiple processors.

This may be a serious shortcoming for multiple processor systems. This thread model is used by:

Green Threads (a thread leibrary available for Solaris) and GNU Portable Threads

4.10 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Many-to-One Model – a Visual DepictionMany-to-One Model – a Visual Depiction

Availability of multiple processors is no help.

Serious disadvantage on very modern architectures.

4.11 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Thread Models: One-to-One ModelThread Models: One-to-One Model

Here, each user-level thread maps to a specific kernel thread. This model clearly increases performance and concurrency. IN this approach, if one thread issues a system call that might result in a block, other

thread(s) may continue. The Good: Multiple threads may execute on multiple processors thus increasing

performance, throughput, etc.. The Bad: For each user thread, there needs to be a unique kernel thread, but this

requires the operating system to create these kernal threads, which may well impact overall performance.

Solution: Because of this serious constraint, most implementations of the one-to-one model restrict the number of threads that the system will support.

Of course, then this requires overhead to ‘manage’ the number of kernel threads. Then too, what does a user process do when it desires to create a thread and the operating system does not allow this creation because the number of allowed kernel threads is reached?

Examples who use the one-to-one model: Windows NT/XP/2000 Linux Solaris 9 and later

4.12 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

One-to-One Model – a VisualOne-to-One Model – a Visual

4.13 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Thread Models: Many-to-Many ModelThread Models: Many-to-Many Model This approach allows many user level threads to be mapped to many kernel threads

via multiplexing. This number may not be one-to-one; user-level threads may map to a smaller (or

equal) number of kernel threads. In some cases, a specific number of threads are allocated to a specific application or to

particular machine. Comparing:

In many to one, developer may create a number of user threads, but blocking becomes an issue and the kernel can only schedule a single thread at a time for CPU cycles.

In one-to-one, there’s greater concurrency due to the increased number of kernel threads, and a block in one thread does not ‘disable’ the process; but care must be taken to not create too many threads within an application. (This is controllable by the OS)

In many-to-many model, we don’t have either of these shortcomings. Users can create many threads as necessary and corresponding kernel threads may have great concurrency on multiple processors. .

Can you see problems with this scenario?? For a given kernel thread, if a blocking system call is made, the kernel can schedule

another user thread for execution. There are some variations in many-to-many, and one such implementation bounds a user

thread to a kernel thread. Examples of this: Solaris prior to version 9; Windows NT/2000 with the ThreadFiber

package

4.14 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Many-to-Many ModelMany-to-Many Model

4.15 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Thread LibrariesThread Libraries Programmers need help and receive development help via thread

libraries germane to specific development APIs.. A thread library provides an API for creating and managing

threads. Java has an extensive API for thread creation and management.

There are two primary ways to implement thread libraries: 1. Provide thread library entirely in user space – no kernel

support All code and data structures for the library exist in user

space. And, invoking a local function call to the library in user space

is NOT a system call, but rather a local function call. (this is good).

2. Implement a kernel-level library supported by the OS. Here, code and data structures exist in kernel space. Unfortunately, in invoking a function call to the library, there

is a system call to the kernel for support.

4.16 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Thread Libraries - more

Three primary thread libraries, and we will look at two of these: POSIX Pthreads – can be provided as either a user- or

kernel-level library. Will look at code.

Win32 threads – will not consider Java threads – Here, the Java thread API allows thread

creation and management directly in Java programs. This is very straightforward. Will look at code here too.

Let’s consider an application that is quite simple: The application merely sums the first non-negative integers (0

through some specified integer, N)

4.17 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

PthreadsPthreads Pthreads refers to the POSIX (Portable Operating System

Interface Committee) (also an IEEE standard) standard for defining an API for thread creation and synchronization.

This API specifies behavior of the thread library. Because the specification is ‘behavioral’ it is not an

implementation.’ Thus, how the specification is implemented is at the discretion

of the software designers.

Before we look at some C code, let’s take a break (a short one) from the text and discuss Linux Threads…

I don’t feel that the textbook does a real good job here and kind of leaves us hanging a bit… So:

4.18 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Linux Threads – taken from Operating Systems Internals and Design Principles,

by William Stallings

Traditional Unix systems support a single thread of execution per process; while more modern Unix systems provide support for multiple kernel-level threads per process.

As was true for UNIX, older versions of the Linux kernel offered no support for multi-threading either.

Rather, applications would need to be written with a set of user-library functions, the most popular of which is known as pthread (POSIX thread) libraries with all of the threads mapping into a single kernel process. We have talked about this and how when one thread is blocked, we have issues…

Modern versions of Unix offer kernel-level threads. Linux provides a unique solution in that it does not recognize a distinction

between threads and processes, as we are aware. Using a mechanism similar to the light-weight processes of Solaris, user-level

threads are mapped into kernel-level processes. Multiple user-level threads that constitute a single user-level process are

mapped into Linux kernel-level processes that share the same process ID. What this does is to enable these processes to share resources such as files

and memory and to avoid the need for a context switch when the scheduler switches among processes in the same group.

4.19 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Linux Threads – taken from Operating Systems Internals and Design Principles, by

William Stallings

A new process is created in Linux by copying the attributes of the current process. A new process can be cloned so that it shares resources, such as files, signal handlers, and virtual memory (but no stack sharing…).

When the two processes share the same virtual memory, they function as threads within a single process.

However, no separate type of data structure is defined for a thread.

In place of the usual fork() command, processes are created in Linux using the clone() command.

This command includes a set of flags as arguments (see previous materials). These commands constitute a number of parameters…(see previous notes on this and your textbook).

The traditional fork() system call is implemented by Linux as a clone() system call with all of the clone flags cleared.

4.20 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Linux Threads – taken from Operating Systems Internals and Design Principles, by

William Stallings

When Linux kernel performs a switch from one process to another, it checks whether the address of the memory area (page directory in virtual memory) of the current process is the same as that of the to-be-scheduled process.

If so, then they are sharing the same address space, so that a context switch is basically just a jump from one location of code to another location of code.

Although cloned processes that are part of the same process group can share the same memory space, they cannot share the same user stacks. Recall: the stack is used for parameter passing, return addresses, etc.

Thus the clone() call creates separate stack spaces for each process

End Stallings. P. 196

Now let’s look at some code…

4.21 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Example forthcoming:

This code calculates the sum of the first non-negative N integers.

In a Pthreads program, separate threads may be executed in a specified function, and this is the runner() function shown in the next slide.

When program (next slide) starts to run, there is a single thread of control – namely main(). Within main(), there is some standard uninteresting

(but included) initialization ensuring we are passing the correct number and type of parameters…

Now, let’s get to the interesting part on the next slide…

4.22 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Multithreaded C program using Pthreads APIMultithreaded C program using Pthreads API#include <pthread.h>

#include (stdio.h>

int sum; // this data is shared by the thread(s)

void *runner (void *param); // the thread

int main (int argc, char *argv[ ])

{ pthread_t tid; // the thread identifier All Pthead programs must include pthread.h.

pthread_attr attr; // set of thread attributes

if (argc != 2) { fprintf (stderr, “usage: a.out <integer value > \n”); ..

return -1; // Each thread also has a set of attributes including

} // a stack and scheduling information.

f (atoi (argv[1] < 0) { fprintf (stderr, “%d must be >= 0\n”, atoi (argv[1]));

return -1;

} .

more code next page – the interesting stuff.

4.23 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Closer look: header code extracted… Closer look: header code extracted… { pthread_t tid; // the thread identifier .

pthread_attr attr; // set of thread attributes .. Each thread also has a set of attributes if (argc != 2) { fprintf (stderr, “usage: a.out <integer value > \n”); including a stack and scheduling information return -1;

. }

f (atoi (argv[1] < 0) { fprintf (stderr, “%d must be >= 0\n”, atoi (argv[1]));

return -1; }

// get the default attributes ===================================pthread_attr_init (&attr);// create the threadpthread_create (&tid, &attr, runner, argv[1]); // Create thread with simple function call w/ thread id and attributes // wait for the thread to exit // must also pass the function name where new thread starts execution.pthread_join (tid,NULL); // Lastly, we are passing the command line parameter, the N to sum up

// Once created, process has two threads: main and runner; printf (“sum = %d\n”,sum); // After creation, parent waits for thread to complete.

} // (runner calls pthread.exit(0). Then it prints the sum.// ============================= done for spacing ==================

// the thread will begin control in this functionvoid *runner (void *param) // easy to see the functionality here in this thread. { int i, upper = atoi(param);

sum = 0;for (i = 1; i <= upper; i++)

sum += i;pthread.exit(0); // pthread.exit(0) - this is part of the pthread API to end the thread…

} // end runner

4.24 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Java Threads using the Java APIJava Threads using the Java API// Java has a ‘rich set’ of features for the creation and management of threads. All Java

programs comprise at least a single thread of control.

// Even main() runs as a single thread in the JVM.

In Java there are two approaches to creating threads. We choose the more popular one where we define a class that implements the Runnable interface.

From you knowledge of Java and interfaces, the Runnable Interface is defined as:

public interface Runnable

{

public abstract void run ();

}

Of course as an interface, it is an abstract class and thus cannot be instantiated.

But as an interface, a concrete class must ‘implement’ the interface…

So an implementing class must implement the run() method in Runnable.

We are going to do the same thing: sum the first N non-negative integers.

Let’s look at code:

4.25 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Multithreaded Java program using Java API (1 of 2)Multithreaded Java program using Java API (1 of 2) class Sum // See next page for driver. But first consider the code here below:

{ // no constructor…

private int sum;

public int getSum() {

return sum;

} // end sum

public void setSum (int sum) {

this.sum = sum;

} // end setSum

} // end class Sum ==========================================================================

class Summation implements Runnable // Summation class implements Runnable. (it must implement run() )

{ // Thread creation is done by creating an object instance of the thread

private int upper; // and passing the Constructor a Runnable object. See next slide)

private Sum sumValue; // Note creating a Thread object doesn’t create a new thread. It is the start()

// method that actually creates the new thread in the next slide..

public Summation (int upper, Sum sumValue) {

this.upper = upper;

this sumValue = sumValue;

} // end Summation

public void run() {

int sum = 0;

for (I = 0; I <= upper; i++0

sum += I;

sumValue.setSum(sum);

} // end run()

} // end Summation

4.26 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Multithreaded Java program using Java API (2 of 2)Multithreaded Java program using Java API (2 of 2) public class Driver

{

public static void main(String {} args) {

if (args.length > 0 {

if (Integer.parseInt(args[0]) < 0)

System.err.println (args[0] + “ must be >= 0.”);

else {

// create the object to be shared

Sum sumObject = newSum(); // create sumObject of type Sum for thread creation ahead

int upper = Integer.parseInt (arg[0]); // get argument from command line…

thread thrd = new thread (new Summation (upper, sumObject)); // creates the thread!

both statements // Note: Thread is passed Runnable object.

needed to start thread. thrd.start(); // actually causes the thread to be created!

// Calling start() brings about allocation of memory and initializes new thread in the JVM, and

// start() calls the run() method (in our behalf) making the thread eligible to be run by the JVM.

try {

thrd.join(); // main ‘waits’ for termination of the thread…Then it prints results.

System.out.println (“The sum of “+upper+” is “+sumObject.getsum());

}

catch (InterruptedException ie) { }

} // end else

} // end upper if

else

System.err.println (“Usage: Summation <integer value>”);

} // end main() | // end Driver

Arguments to Constructor in Summation which implements Runnable!

Start here

4.27 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Finishing Threads with Java APIFinishing Threads with Java API So, when the summation program is executed, two threads are

created by the JVM:

First, we have the parent thread, of course, which starts execution in the main() method that we are used to.

Second thread is created from the start() method, thrd.start(), on the ‘thread’ object.

The child thread starts executing in the run() method in the Summation class, which outputs the value of the summation by calling setSum(sum) within sumValue object.

In summary: Java threads are managed by the JVM

Java threads may be created by:

Extending thread class and

Implementing the Runnable interface

4.28 Silberschatz, Galvin and Gagne ©2005Operating System Concepts

Java Thread States Java Thread States

This is a good model:Notice that the thread can block for I/O, etc...

End of Chapter 4.1End of Chapter 4.1