Overview
Multithreading Models
Threading Issues
Linux Threads
Pthreads
Threads Overview
A process can contain multiple threads of control
A thread (or lightweight process) contains:
A thread ID
A program counter
A register set
A stack
Threads belonging to the same process share:
Code section
Data section
Open files
A process with multiple threads of control can do multiple tasks at a time
Single and Multithreaded Processes
Benefits of Threads
Increase responsiveness to user
Thread creation faster than process creation
Thread context switch faster than process context switch
Utilization of multiprocessor architectures: threads belonging to the same process may run in parallel on different processors
User Threads
Supported by a user-level thread library
Library handles thread creation, scheduling, and management with no support from kernel
Advantage: user-level threads are fast to create and manage
Drawback: a user thread performing a blocking system call will cause entire process to block
Example user thread libraries: POSIX Pthreads, Mach Cthreads, Solaris 2 UI-threads
Kernel Threads
Supported by the operating system
Kernel handles thread creation, scheduling, and management
Advantages:
If a thread performs a blocking system call, the kernel can schedule another thread in the application for execution
Kernel can schedule threads on different processors in a multiprocessor system
Drawback: slower to create and manage than user threads
Most modern operating systems support kernel threads
Multithreading Models
Many systems support both user level and kernel level threads
How to map user level threads to kernel level threads?
Many-to-One
One-to-One
Many-to-Many
Many-to-One
Many user-level threads mapped to one kernel thread.
Allow the developer to create as many user threads as she wishes
Entire process will block if a thread makes a blocking system call
Multiple threads can’t run in parallel on multiprocessors
Example: green threads (a user-level thread library) in Solaris 2
Many-to-One Model
One-to-One
Each user-level thread mapped to a kernel thread
Allow another thread to run when a thread blocks
Allow multiple threads to run in parallel on multiprocessors
Most systems limit the number of threads supported due to overhead of creating kernel level threads
Examples: Windows NT/2000, OS/2
One-to-one Model
Many-to-Many Model
Many user level threads mapped to a smaller or equal number of kernel threads.
Avoid limitations of both many-to-one and one-to-one models
Developers can create as many user threads as necessary,
Kernel threads corresponding to the user threads can run in parallel on multiprocessors
Kernel can schedule another thread for execution if a thread blocks
Examples: Solaris 2, Windows NT/2000 with the fiber library
Many-to-Many Model
Threading Issues: fork and exec
What if one thread in a program calls fork?
Some UNIX systems have two versions of fork:
The new process duplicates all threads
The new process duplicates only the thread that invoked fork
What if one thread in a program calls exec?
The new program replaces the entire process (including all threads)
If exec is called immediately after fork, duplicating all threads is unnecessary
Threading Issues: Cancellation
Thread cancellation: killing a thread before it has completed
Asynchronous cancellation: the target thread is immediately cancelled
Can cause problems if the target thread is in the middle of allocating resources, performing I/O, or updating shared data
Deferred cancellation: the target thread periodically checks if it should terminate
Allow cancellation at safe points
Pthreads refer to safe points as cancellation points
Threading Issues: Signal Handling
A signal is used to notify a process about the occurrence of an event
Synchronous signal: sent from a process to itself
E.g., division by 0, illegal memory access
Asynchronous signal: sent from external source
E.g., timer expire, ctrl-c
A signal may be handled by
Default signal handler:
Every signal has one
Run by kernel
User-defined signal handler: override the default signal handler
Threading Issues: Signal Handling
If a process has several threads, where to deliver a signal?
To the thread to which the signal applies (e.g. division by 0)
To all the threads in the process (e.g. ctrl-c)
To certain threads in the process, i.e., those that are not blocking the signal
Typically a signal is delivered only to the first thread that is not blocking the signal
Assign a thread to receive and handle all signals for the process
Threading Issues: Thread Pools
Motivating example: a web server creates a new thread to service each request
Two concerns:
Overhead to create thread; thread discarded after it has completed its work
No limit on the number of threads created, may exhaust system resources
One solution: thread pools
Create a pool of threads at process startup
Request comes in: wake up a thread from pool, assign the request to it. If no thread available, server waits until one is free
Service completed: thread returns to pool
Benefits:
Faster to wake up an existing thread than creating a new thread
Pool limits the number of threads in system
Linux Threads
clone system call used to create kernel level threads
Allow child to share resources with parent (e.g. memory space, open files, signal handlers)
Parameter ‘flags’ indicates the extent of sharing
How to allow sharing?
Kernel data structure for a process created by clone contains pointers to the data structures of the parent
process
Pthreads
The POSIX standard (IEEE 1003.1c) API for thread creation and synchronization.
The standard specifies interface only, implementation is up to developer.
Common in UNIX operating systems.
On Linux machines
#include
Link with the pthread library
g++ threads.cc -lpthread
Pthreads: Creating
int pthread_create(pthread_t * thread, pthread_attr_t * attr,
void * (* start_routine) (void *), void * arg);
On success
A new thread is created with attributes “attr” (NULL=default), id of new thread is placed in “thread”.
New thread starts executing function “start_routine” with parameter “arg”
New thread executes concurrently with the calling thread
New thread runs until it returns from “start_routine” or it calls “pthread_exit”
Return 0
On failure
Return non-zero error code
pthread_create Example
void* my_thread (void *arg)
{
char *msg = (char *) arg;
cout << “Thread says “ << msg <<“\n”;
}
int main()
{
pthread_t t;
char *msg = “Hello World”;
pthread_create(&t, NULL, my_thread, msg);
return 0;
}
Pthreads: Waiting
int pthread_join(pthread_t th, void **thread_return); //wait for
a thread to terminate
th: the thread to wait for
thread_return: NULL or address of buffer to store return value of th
When a thread terminates, its memory resources (thread ID and stack) are not deallocated until another thread performs pthread_join on it.
At most one thread can wait for the termination of a given thread.
Return 0 on success, non-zero on failure
No comments:
Post a Comment