Week 02
Week 02
Week 02
pid = fork();
if (pid == 0) {
code to be executed by slave
} else {
code to be executed by parent
}
if (pid == 0) exit(0); else wait(0);
.
.
❑ All the variables in the original program are duplicated in each process,
becoming local variables for the process.
❑ They are assigned the same values as the original variables initially. The
forked process starts execution at the point of the fork.
Stack
Interrupt routines
Files
Stack Thread
Instruction Pointer
Interrupt routines
Stack Thread
Instruction Pointer
Files
Thread 1
Thread 2
FIT3143 Parallel Computing 13
Thread Basics
A thread is a single stream of control in the flow of a program.
Code segment for computing the product of two dense matrices of size n x n:
for(row = 0; row < n; row++)
for(column = 0; column < n; column++)
c[row][column] = dot_product(get_row(a,row), get_col(b,col));
▪ POSIX.1c standard
▪ C language interface
▪ Threads exist within same process
▪ All threads are peers
• No explicit parent-child model
• Exception: “main thread” holds process information
pthread_t *tid
handle of created thread
const pthread_attr_t *attr
attributes of thread to be created
void *(*function)(void *)
function to be mapped to thread
void *arg
single argument to function
❑ Spawn a thread running the function
❑ Thread handle returned via pthread_t structure
❑ Specify NULL to use default attributes
❑ Single argument sent to function
❑ If no arguments to function, specify NULL
❑ Check error codes!
EAGAIN - insufficient resources to create thread
EINVAL - invalid attribute
FIT3143 Parallel Computing 21
Example I: Thread Creation
#include <stdio.h>
#include <pthread.h>
main() {
pthread_t tid;
pthread_create(&tid, NULL, hello, NULL);
}
Possible outcomes:
❑ Message “Hello Thread” is printed on screen
❑ Nothing printed on screen. This outcome is more likely that previous. Main
thread is the process and when the process ends, all threads are cancelled, too.
Thus, if the pthread_create call returns before the O/S has had the time to set up
the thread and begin execution, the thread will die a premature death when the
process ends.
❑ This is the better way to have one thread wait for the completion of another thread.
❑ Pthread_join will block until the thread associated with the pthread_t handle has
terminated. The second parameter returns a pointer to a value from the thread being
joined. This value can be “sent” from the joined thread by use of return or
pthread_exit(). The type of the returned value is (void *) since this is the return type of
the function that was used in the pthread_create call.
❑ pthread_join() can be used to wait for one thread to terminate. There is no single
function that can join multiple threads.
#include <stdio.h>
#include <pthread.h> Better example of waiting for
#define NUM_THREADS 4 threads, in this case, multiple
threads doing the same
void *hello (void *arg) { function. Notice that there must
printf(“Hello Thread\n”); be one call for each thread
} needed to be “joined” after
termination. Also, the joins are
main() { done in the order of the
pthread_t tid[NUM_THREADS]; thread’s creation. Thus, if the
for (int i = 0; i < NUM_THREADS; last thread created is the first to
i++) finish, it will not be joined until
pthread_create(&tid[i], NULL, the previous threads have
hello, NULL); finished.
// from main():
for (int i = 0; i < numThreads; i++) {
tNum[i] = i;
pthread_create(&tid[i], NULL, threadFunc,
&tNum[i]);
}
pthread_mutex_t *mutex
mutex to be initialized
const pthread_mutexattr_t *attr
attributes to be given to mutex
pthread_mutex_unlock
❑ Two problems that can arise from using condition variables. Both of these are taken
care of when using the algorithm on the next slide.
❑ Lost signal – condition has no memory, thus, if no thread is waiting on the condition
variable, all signals on that condition variable will do nothing. If a thread “blindly”
waits on a condition variable, it can be deadlocked if there is no other signal to wake it
up. (Thus, the conditional expression is checked before a thread will wait.)
❑ Spurious wakeups – on some multi-processor systems, condition variable code could be
slowed down if all signals were to be made predictable. (Thus, the correct algorithm
requires a retest of the conditional expression after a thread is signaled after waiting
on the condition variable. Spurious wakeups should put the thread back to waiting on
the condition variable.)
❑ Condition variables are always paired with a mutex. The mutex is used to protect
access any variables that are used in the conditional expression. This access will be
in testing the conditional and updating variables that are involved in the
conditional test. In other words, the mutex must protect the code from race
conditions between a thread signaling the condition variable with a thread waiting
on the condition variable.
❑ The only job of the mutex should be to protect variables used in the conditional.
This will ensure proper utilization of condition variables and prevent lock
contention performance problems when a mutex is overloaded by being used in
other parts of the code.
Negation of condition
needed to proceed
acquire mutex;
Mutex is automatically released
Avoids problems with lost while (conditional is true) when thread waits
and spurious signals wait on condition variable;
perform critical region computation;
update conditional; May be optional
signal sleeping thread(s);
release mutex;
❑ Conditional in while test is the negation of the condition needed to proceed in to the critical
region. For example, if (x > 0) is needed to get past condition variable, test will be while (x<=
0). This is the most important part of the algorithm presented. The while test prevents…
❑ LOST SIGNALS since the conditional is tested before the thread waits. If the condition is
false (able to proceed), the thread will not wait
❑ SPURIOUS WAKEUP since the thread will retest the while condition. If the condition is still
true (not able to proceed), the thread will go back to waiting. [This is not prevented, but
handled properly so that the code works as expected even when spurious wakeups occur.]
❑ As will be seen shortly, the mutex is released when the thread waits on the condition variable.
❑ The “update” and “signal” steps can be done external to the algorithm, dependent upon the
requirements of the application. However, programmer must be sure the variables involved
are updated while protected by the mutex associated with the condition variable.
FIT3143 Parallel Computing 35
Condition Variables
pthread_cond_init, pthread_cond_destroy
initialize/destroy condition variable
pthread_cond_wait
thread goes to sleep until signal of condition variable
pthread_cond_signal
signal release of condition variable
pthread_cond_broadcast
broadcast release of condition variable
pthread_cond_t *cond
condition variable to be initialized
const pthread_condattr_t *attr
attributes to be given to condition variable
❑ The calling thread will block (sleep) until such time as a pthread_cond_signal is issued that
wakes up the threads. Upon going to sleep, the mutex (held because the thread has the
mutex via the standard algorithm already presented) is unlocked. This will allow other
threads that may be wanting to wait on the condition variable to enter the wait algorithm
and for threads that need to update the variables used in the conditional expression the
chance to lock the mutex to make changes.
❑ Before the pthread_cond_wait function returns (after the thread receives a signal), the
mutex will be automatically reacquired (locked). This gives the thread mutually exclusive
access to the conditional expression variables (if needed) and why the standard algorithm
releases the lock when done.
FIT3143 Parallel Computing 38
pthread_cond_signal
If the signaling thread does not hold the associated mutex, the problem
when using thread priorities would develop if a high priority thread is
waiting and lower priority thread might lock the mutex (at the start of the
condition variable algorithm) before the higher priority thread got the
chance to reawaken and lock the mutex. By holding the mutex when
signaling, in this situation, the lower priority thread will block in the
attempt to lock the mutex and the higher priority thread will be given
preference to acquire the mutex when it is released by the signaling thread.
FIT3143 Parallel Computing 39
pthread_cond_broadcast
Each thread waiting on the condition variable will be signaled and, in turn,
as the mutex becomes available, return from the pthread_cond_wait call.