synchronization constructs in C
Locks (mutex)
Have the type
pthread_mutex_t
Allocation and initialization
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
Dynamic allocation (init and destroy)
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
Acquire and release
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
trylock
is not held by other tread: acquires lock if available, else returns
EBUSY
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
...
pthread_mutex_lock(&lock);
... // critical section
pthread_mutex_unlock(&lock);
Recursive lock
Recursive lock possible with pthreads:
Locking and unlocking done by same thread multiple times.
But the number of lock-unlock pairs must stay consistent.
pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;pthread_mutex_lock(&lock);
pthread_mutex_lock(&lock);
... // perhaps in "thread_safe" function
pthread_mutex_unlock(&lock);
pthread_mutex_unlock(&lock);
Reader/writer locks
are more flexible: allow concurrent reading but not writing
allow several threads to aquire lock for reading shared variables but only a single thread is acquired for writing.
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
Once locks
Mutex-like variable ensures that some initialization routine
init_routine
is executed exactly once.
#include <pthread.h>
pthread_once_t once_init = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *once_init, void (*init_routine)(void)));
Spinlocks
Same semantic as the other mutex locks but different implementation/pragmatics.
Active waiting with
while(!flag);
Optimized for short, critical sections and only one thread per core.
Possibly faster on dedicated (parallel) apps on dedicated systems.
In contrast to other mutex locks it can not be suspended (put to sleep) by OS and resumed when lock is released. → No expensive OS suspension required.
Bad performance on systems with more threads than processors.
#include <pthread.h>
int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);int pthread_spin_unlock(pthread_spinlock_t *lock);
Condition variables
Allocation and initialization
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond, const pthread_cond_attr *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
Waiting for signal
Thread suspended (waits), lock is temporarily relinquished (released).
When resumed later by a signal from other thread, it has acquired lock.
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
Signaling
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond); // single thread
int pthread_cond_broadcast(pthread_cond_t *cond); // all threads
Barrier
Nonstandard pthreads barrier
#include <pthreads.h>
int pthread_barrier_init(pthrad_barrier_t *barrier, pthread_barrierattr_t *attr, unsigned count);
int pthread_barrier_destroy(pthread_barrier_t *barrier);
int pthread_barrier_wait(pthread_barrier_t *barrier);
count
= number of threads to synchronize.
Executing thread blocks until
count
threads have been reached.
Semaphores
Semaphores
Can be shared across processes
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);int sem_wait(sem_t *sem); // decrement
Int sem_trywait(sem_t *sem);int sem_post(sem_t *sem); // increment
Atomic operation
Atomic operation
Special hardware operation in  .
in modern multi-core processors:
fetch_and_inc(a); // atomically return old value of a, increment
fetch_and_dec(a); // atomically return old value of a, decrement
fetch_and_add(a,x); // FAA - atomically return old value of a, add x to atest_and_setcompare_and_swap(e,u,a); // if content of a is equal to e, replace content of a with u, atomically, return success status (CAS)load_linked
store_conditional //(LL/SC)