# CS 5220
## Shared memory
### Pthreads
## 22 Sep 2015
### Shared memory programming model
Program consists of *threads* of control.
- Can be created dynamically
- Each has private variables (e.g. local)
- Each has shared variables (e.g. heap)
- Communication through shared variables
- Coordinate by synchronizing on variables
- Examples: OpenMP, *pthreads*, Cilk, Java threads
### Concrete code: pthreads
- pthreads = POSIX threads
- Standardized across UNIX family
- Fairly low-level
- Heavy weight?
Thread birth and death
Thread is created by forking.
When done, join original thread.
### Thread birth and death
void thread_fun(void* arg);
pthread_t thread_id;
pthread_create(&thread_id, &thread_attr,
thread_fun, &fun_arg);
// ...
pthread_join(&thread_id, NULL);
Mutex
Allow only one process at a time in critical section
(red).
Synchronize via locks, aka mutexes (mutual exclusion vars).
### Mutex
pthread_mutex_t l;
pthread_mutex_init(&l, NULL);
// ...
pthread_mutex_lock(&l);
/* Critical section here */
pthread_mutex_unlock(&l);
// ...
pthread_mutex_destroy(&l);
Condition variables
Thread waits until condition holds (e.g. work available).
Condition variables
pthread_mutex_t l;
pthread_cond_t cv;
pthread_mutex_init(&l)
pthread_cond_init(&cv, NULL);
/* Thread 0 */
mutex_lock(&l);
add_work();
cond_signal(&cv);
mutex_unlock(&l);
/* Thread 1 */
mutex_lock(&l);
if (!work_ready)
cond_wait(&cv, &l);
get_work();
mutex_unlock();
pthread_cond_destroy(&cv);
pthread_mutex_destroy(&l);
Barriers
Computation phases separated by barriers.
Everyone reaches the barrier, then proceeds.
### Barriers
pthread_barrier_t b;
pthread_barrier_init(&b, NULL, nthreads);
// ...
pthread_barrier_wait(&b);
// ...
### Example: Work queues
- Job composed of different tasks
- Work gang of threads to execute tasks
- Maybe tasks can be added over time?
- Want dynamic load balance
### Example: Work queues
Basic data:
- Gang of threads
- Work queue data structure
- Mutex protecting data structure
- Condition to signal work available
- Flag to indicate all done?
### Example: Work queues
task_t get_task() {
task_t result;
pthread_mutex_lock(&task_l);
if (done_flag) {
pthread_mutex_unlock(&task_l);
pthread_exit(NULL);
}
if (num_tasks == 0)
pthread_cond_wait(&task_ready, &task_l);
// ... Remove task from data struct ...
pthread_mutex_unlock(&task_l);
return result;
}
### Example: Work queues
void add_task(task_t task) {
pthread_mutex_lock(&task_l);
... Add task to data struct ...
if (num_tasks++ == 0)
pthread_cond_signal(&task_ready);
pthread_mutex_unlock(&task_l);
}
### The problem with pthreads
Portable standard, but...
- Low-level library standard
- Verbose
- Makes it easy to goof on synchronization
- Compiler doesn’t help out much
OpenMP is a common alternative.