Chapter 4 PowerPoint

advertisement
Operating System Concepts
chapter 4
CS 355
Operating Systems
Dr. Matthew Wright
Threads
Relation to processes
• Threads exist as subsets of processes
• Threads share memory and state information within a process
• Switching between threads is faster than switching between processes
Threads
Benefits
•
•
•
•
Responsiveness: one thread can respond to the user if another is busy
Resource sharing: threads share resources by default
Economy: threads are easier to create and maintain than processes
Scalability: use multiple processors easily
Challenges
•
•
•
•
•
Dividing activities: Which tasks can run concurrently?
Balance: How to use each processor effectively?
Data splitting: dividing the data between different cores
Data dependency: Does one task depend on data from another?
Testing and debugging: more difficult when using threads
User vs. Kernel Threads
User Threads
• Managed by the application
• The kernel is not aware of user threads
• Programmed using a thread library
(e.g. Pthreads, Win32, Java)
• Many-to-one mapping
Kernel Threads
• Managed by the kernel
• Applications don’t have to manage
threads
• Programmed using an API
• Most modern operating systems
support kernel threads
• One-to-one mapping
user threads
threads
library
user space
kernel space
process
user threads
user space
kernel space
kernel
threads
process
User vs. Kernel Threads
Advantages of user threads over kernel threads
• Thread switching does not require kernel mode
• Thread scheduling can be application-specific
• User threads can run on any operating system, iwthout support
from the kernel
Disadvantages of user threads compared to kernel threads
• If one user thread executes a system call that blocks its process, all
other threads within that process are blocked
• Threads cannot execute concurrently if multiple processors are
available
Combined Approach
Some operating systems
combine the previous two
approaches.
• Thread creation is done in user
space.
• Thread scheduling and
synchronization done in user or
kernel space.
• User threads from an
application are mapped to
some (smaller or equal)
number of kernel threads.
• Many-to-many mapping or a
two-level model
user threads
threads
library
user space
kernel space
kernel
threads
process
process
Thread Libraries
A thread library provides programmer with API for creating and
managing threads
Two primary ways of implementing:
• Library entirely in user space
• Kernel-level library supported by the OS (invoke functions by
system calls)
POSIX Pthreads
• A specification, not an implementation, for thread creation and
synchronization
• May be provided either as user-level or kernel-level
• API specifies behavior of the thread library, implementation is up
to development of the library
• Common in UNIX operating systems (Solaris, Linux, Mac OS X)
Example: C program using Pthreads
/**
* Pthread example program
*
* @author Gagne, Galvin, Silberschatz
* Operating System Concepts with Java, 8th ed, fig. 4.9
*/
#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 */
pthread_attr_t attr; /* set of attributes for the thread */
if (argc != 2) {
fprintf(stderr,"usage: a.out <integer value>\n");
return -1;
}
if (atoi(argv[1]) < 0) {
fprintf(stderr,"Argument %d must be non-negative\n",atoi(argv[1]));
Java Threads
Java threads are managed by the JVM
Java threads may be created in two ways:
• Extend the Thread class and override its run() method
• Implement the Runnable interface (preferred)
public interface Runnable
{
public abstract void run()
}
Creating a Java thread using a Runnable object:
1. Create an instance of the Thread class and pass the constructor
a Runnable object
2. Call the start() method of the thread object
Java Example
/**
* Create a separate thread by implementing the Runnable interface.
*
* @author Gagne, Galvin, Silberschatz
* Operating System Concepts with Java, 8th Ed., Fig. 4.11
*/
class Sum
{
private int sum;
public int get() {
return sum;
}
public void set(int sum) {
this.sum = sum;
}
}
class Summation implements Runnable
{
private int upper;
private Sum sumValue;
Java Threads
Note:
• If two Java threads are to share data, references to the shared
objects must be passed to the threads.
• The join() method causes the parent thread to wait for its child
to finish processing, and this can throw an
InterruptedException.
• Java doesn’t specify how the JVM maps java threads to the
underlying operating system.
• Java threads may be in one of six states: new, runnable, blocked,
waiting, timed waiting, terminated
• Java provides methods to determine the state of a thread:
– isAlive() returns true if a thread is started, but not terminated
– getState() returns the state as an enumerated data type
Java Threads
Java Example
/**
*/**
Factory class that creates the MessageQueue class and
/**
*
Theproducer
message and
queue
* the
/**
consumer threads.
*
The
producer
class
*
* * * The consumer class
@author
Gagne,Galvin,
Galvin,Silberschatz
Silberschatz
* *@author
*@author
Gagne,
*
Gagne,
Galvin,
Silberschatz
Operating
System
Concepts
withJava,
Java,8th
8thed,
ed,Fig.
Fig.4.13
3.21
* *Operating
*
@author
System
Gagne,
Concepts
Galvin,
with
Silberschatz
*
Operating
System
Concepts
with
Java,
8th
ed,
Fig.
4.14
*/*/*/* Operating System Concepts with Java, 8th ed, Fig. 4.15
*/
import
java.util.Vector;
import
java.util.Date;
import
java.util.Date;
import java.util.Date;
publicclass
classFactory
MessageQueue<E> implements Channel<E>
public
class
Producer
implements Runnable
{ { { class Consumer implements Runnable
private
Vector<E>
queue;
public
{private
static
void main(String[]
Channel<Date>
queue; args) {
//private
create the
Channel<Date>
message queue
queue;
public
MessageQueue()
{
Channel<Date>
queue = new MessageQueue<Date>();
public
Producer(Channel<Date>
queue) {
queue
=
new
Vector<E>();
public
Consumer(Channel<Date>
queue) {
= queue;
}// this.queue
this.queue
the producer
= queue;and consumer threads
} create
Thread
}
producer = new Thread(new Producer(queue));
public
void
send(E
item)
{
Thread
consumer
= new
Thread(new
Consumer(queue));
public
void
run()
queue.addElement(item);
{ public void run() {
}//
start
Datemessage;
the
message;
threads
Date
producer.start();
public
E receive()
consumer.start();
while
(true){ {
while
(true)
== 0)
} if {(queue.size()
SleepUtilities.nap();
//nap for awhile
return
null;
}
SleepUtilities.nap();
= new Date();
elsemessage
// consume an item from the buffer
Creating and Cancelling Threads
Semantics of fork() and exec() system calls
• Does fork() duplicate only the calling thread or all threads? It could
be implemented either way.
• The exec() system call typically replaces the entire process (all
threads) with a new program.
Thread cancellation
• Terminating a thread before it has finished
• Two general approaches:
– Asynchronous cancellation terminates the target thread
immediately
– Deferred cancellation allows the target thread to periodically check
if it should be cancelled
• If a thread is cancelled, how do we ensure that the system is stable?
• Java provides an interrupt status for each thread.
Java Example
/**
* Example program illustrating thread interruption.
*
* @author Gagne, Galvin, Silberschatz
* Operating System Concepts with Java, 8th Ed., Fig. 4.16
*/
public class InterruptibleThread implements Runnable
{
/**
* This thread will continue to run as long
* as it is not interrupted.
*/
public void run() {
while (true) {
/* do some work for awhile */
if (Thread.currentThread().isInterrupted()) {
System.out.println("I'm interrupted!");
break;
}
}
/* clean up and terminate */
}
Signal Handling
• Signals are used in UNIX systems to notify a process that a
particular event has occurred.
• Synchronous signals: delivered to the thread that caused the signal
– examples: division by zero, illegal memory access
• Asynchronous signals: generated by an external event, delivered to
a process or thread
– examples: user input, user termination of process
• A signal handler is used to process signals.
• Options:
– Deliver the signal to the thread to which the signal applies
– Deliver the signal to every thread in the process
– Deliver the signal to certain threads in the process
– Assign a specific thread to receive all signals for the process
Thread Pools
• Idea: create a number of threads, place them in a “pool” where
they await work.
• Advantages:
– Usually slightly faster to service a request with an existing thread
than to create a new thread.
– Allows the number of threads in an application to be bound to
the size of the pool, avoiding the creation of an extremely large
number of threads.
• In Java, the java.util.concurrent package facilitates
thread pools via the Executor interface.
Thread-Specific Data
• Allows each thread to have its own copy of data
• Useful when you do not have control over the thread creation
process (i.e., when using a thread pool)
• Java provides the ThreadLocal class for thread-specific data.
• Example…
Java Example
/**
*/**
Example program illustrating thread-specific data.
/**
*
thread performs a transaction and every transaction is
* *Each
This
service
fulfills
transactions
are purposes,
performed by
identified
by Galvin,
aclass
separate
serial
number. Forwhich
logging
* *@author
Gagne,
Silberschatz
*weseparate
threads.
Because
a transaction
may resultbyineach
an error,
may wish
to log
the
transaction
being
performed
thread.we
* *Operating
System
Concepts
with
Java,
8th
Ed.,
Fig.
4.18
and
4.19
* need to record the error. However, since there is only a static
*/ */* instance of this class, there is only one copy of errorCode. If an
* error
occurs
in one Runnable
thread, it will set the value of errorCode,
class
Worker
implements
public
class
TSD
* however another thread may set it to a different value. The solution
{ { * to this is to use ThreadLocal copies of errorCode. Every thread that
private static Service provider;
* causes an error will set its own copy of errorCode.
public
static void main(String[] args) {
*/
public
void run() {
java.util.concurrent.ExecutorService
pool =
provider.transaction();
class
Service java.util.concurrent.Executors.newCachedThreadPool();
System.out.println(Thread.currentThread().getName()
+ " > " +
{
+ " < ");
for
(intstatic
i = 0;void
i < transaction()
5;provider.getErrorCode()
i++) {
public
{
} // just for kicks, use a thread pool
// fulfill some kind of transaction service
}
pool.execute(new
Worker());
try { Thread.sleep(
(int) (Math.random() * 1000) ); }
} catch (InterruptedException ie) { }
pool.shutdown();
// some operation where an error may occur
}
try {
}
int num = (int) (Math.random() * 2);
double recip = 1 / num;
}
catch (Exception e) {
Scheduler Activations
• Both many-to-many and two-level models require
communication between the kernel and the thread
library to maintain the appropriate number of kernel
threads allocated to the application.
• Many systems use an intermediate data structure
known as a lightweight process (LWP) between user
threads and kernel threads.
• The LWP appears as a virtual processor to user threads.
• Scheduler activations provide upcalls: a communication
mechanism from the kernel to the thread library
• Example: If a thread blocks to wait for I/O, the kernel
makes an upcall to the thread library.
• This communication allows an application to maintain
the correct number kernel threads.
user
thread
LWP
kernel
threads
Windows
• Windows uses the Win32 and Win64 APIs
• Implements a one-to-one mapping of user threads to kernel
threads
• Offers a fiber library to provide support for the many-to-many
model
• Each thread contains
– A thread id
– Register set representing the status of the processor
– Separate user and kernel stacks, for when the thread is running
in user mode and kernel mode
– Private data storage area
• The register set, stacks, and private storage area are known as the
context of the threads
Windows
The primary data
structures of a thread
include:
• ETHREAD (executive
thread block): includes
pointers to the process
that owns the thread
and to the KTHREAD
• KTHREAD (kernel thread
block): scheduling and
synchronization
information
• TEB (thread
environment block):
user-mode data
Linux Threads
• Linux refers to them as tasks rather than threads
• Thread creation is done through clone() system call
– clone() requires a set of parameters that determine how
much sharing takes place between parent and child tasks
• The Linux kernel includes a data structure for each task that
contains pointers to structures where data is stored (e.g. list of
open files, signal-handling information, virtual memory)
– fork() creates a new task and copies the data structure of
parent process
– clone() creates a new task and allows the new data structure
to point to that of the parent
Download