Thread Motivation
Processes and Threads
Process Properties
Thread View
Thread Execution Environment
The process is the execution environment for a family of threads
– A group of threads share the same resources (files, memory space, etc.)
* Since threads are associated with their process, they are able to use the resources belonging to the process and duplicate only the required resources, such as the PC, stack, and SP, needed by the OS to schedule threads independently from their processes
– This makes creating and switching between threads belonging to same process very simple and much more efficient than creating or switching between processes
* Although switching for threads belonging to different processes is still as complex as classic process switch
Thread Properties
Since a thread exists within a process, if a process terminates, so does the thread
Thread Consequences
POSIX Threads
The pthreads Library
The pthread.h library includes the following operations:
– pthread_create create a new thread
– pthread_detach detach a thread, to release its resources when thread terminates
– pthread_exit terminate calling thread, without terminating process
– pthread_join wait for a specified thread to terminate
– pthread_equal compare thread IDs
– pthread_kill send a specified signal to a thread
– pthread_self obtain the ID of the calling thread
Creating Threads
int pthread_create(pthread_t tid, const pthread_attr_t tattr, void (start_routine)(void *), void *arg);
– tid: an unsigned long integer that indicates a thread’s id
– tattr: attributes of the thread – usually NULL
– start_routine: the name of the function the thread starts executing
– arg: the argument to be passed to the start routine – only one
Joining Threads
Joining is one way to accomplish synchronization between threads where the process waits for all threads to complete
– We call the function pthread_join() once for each thread
Wait for Completion of a Thread
int pthread_join(thread_t tid, void **status);
– tid: identification of the thread to wait for
– status: the exit status of the terminating thread – can be NULL
Exiting a Thread
void pthread_exit(void *status);
– status: the exit status of the thread – passed to the status variable in the pthread_join() function of a thread waiting for this one
Detaching a Thread
int pthread_detach(pthread_t tid);
– tid: identification of the thread to detach
Memory in Processes vs Threads
Thread Safety
Race condition
Thread-Safe Functions
Data Race Example
Synchronizing Threads
3 basic synchronization primitives / constructs / operations
– Mutex Locks (like a gatekeeper)
* Control thread’s access to the data with simple mutual exclusion
– Condition Variables
* More complex synchronization
* Let threads wait until a user-defined condition becomes true (i.e., based on the value of the data
* Removes polling requirement
– Semaphores
* Signal-based synchronization
* Allows sharing (not wait unless semaphore = 0)
* Access to data granted/blocked based on semaphore value
Mutex Locks definition
Mutex (mutual exclusion) is a special type of variable used to restrict access to a critical section to a single thread at a time
– Guarantee that one thread “excludes” all other threads while it executes the critical section
– When a thread waits on a mutex/lock, CPU resource can be used by others
mutex locks implementation
int pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *mattr);
* mp: a pointer to the mutex lock to be initialized
* mattr: attributes of the mutex – usually NULL
Locking a Mutex
To ensure mutual exclusion to a critical section, a thread should lock a mutex
1.When locking function is called, it does not return until the current thread owns the lock
2.If the mutex is already locked, calling thread blocks
3.If multiple threads try to gain lock at the same time, the return order is based on priority of the threads
* Higher priorities return first
* No guarantees about ordering between same priority threads
int pthread_mutex_lock(pthread_mutex_t *mp);
* mp: mutex to lock
Unlocking a Mutex
When a thread is finished within the critical section, it needs to release the mutex
– Calling the unlock function releases the lock
– Then, any threads waiting for the lock compete to get it
– Very important to remember to release mutex
int pthread_mutex_unlock(pthread_mutex_t *mp);
* mp: mutex to unlock