Pthreads Flashcards
Creating a pthread_t
To create a thread in Pthreads, you use the pthread_create
function, which has the following syntaxpthread t*
const pthread_attr_t* atrr_p
void* (*start_routine)(void*)
void* arg_p
Stopping a pthread_t
A single call to pthread_join
will wait for the thread associated with the pthread_t
object to complete. The syntax of pthread join is
pthread t* thread
void** ret_val_p
Mutex
A mutex (short for mutual exclusion) is a synchronization primitive used to protect shared resources from concurrent access, ensuring that only one thread accesses a critical section at a time.
Initialising a Mutex
To use a mutex, you first need to initialize it using pthread_mutex_init
:
```c
pthread_mutex_t mutex;
const pthread_mutexattr_t* attr
pthread_mutex_init(&mutex, NULL);
~~~
Locking and Unlocking a Mutex
To enter a critical section, a thread must lock the mutex. After finishing the critical section, the thread must unlock the mutex.
```c
pthread_mutex_lock(&mutex);
// Critical section
pthread_mutex_unlock(&mutex);
~~~
NB: When pthread_mutex_lock()
is called and mutex
is already locked, it becomes a blocking call.
Destroying a Mutex
When a mutex is no longer needed, it should be destroyed to free resources.
```c
pthread_mutex_destroy(&mutex);
~~~
Semaphore
Semaphores are synchronization tools used to control access to a resource by multiple threads. Unlike mutexes, semaphores can allow more than one thread to access a critical section simultaneously, based on the semaphore’s value.
Initialising a Semaphore
To initialize a semaphore, you use the sem_init
function, which has the following arguments:
|Type|Variable Name|Comment|
|sem_t*
|sem
|/* out */
|
|int
|pShared
|/* in */
|
|unsigned int
|value
|/* in */
|
```c
#include <semaphore.h>
sem_t semaphore;
sem_init(&semaphore, 0, 1); // 1 is the initial value
~~~</semaphore.h>
-
pShared = 0
implies the semaphore is shared among threads of the same process. - if
pShared != 0
, the semaphore is shared between DIFFERENT processes.
Waiting and Posting a Semaphore
To decrease the semaphore value (wait operation), a thread uses sem_wait
. To increase the semaphore value (post operation), a thread uses sem_post
.
```c
sem_wait(&semaphore);
// Critical section
sem_post(&semaphore);
~~~
Destorying a Semaphore
When a semaphore is no longer needed, it should be destroyed.
```c
sem_destroy(&semaphore);
~~~
Read-Write Locks
Read-write locks allow multiple threads to read from a shared resource concurrently while still providing exclusive access for writing.
Why Lock for Reading?
Locking for reading ensures that data being read is consistent and not being modified by another thread during the read operation, preventing race conditions and maintaining data integrity.
Why Lock for Writing
Locking for writing provides exclusive access to the shared resource, preventing data corruption and ensuring that updates are correctly applied without interference from other threads.
Initializing a Read-Write Lock
To initialize a read-write lock, use pthread_rwlock_init
with the following arguments:
|Type|Variable Name|Comment|
|—|—|—|
|pthread_rwlock_t*
|rwlock
|/* out */
|
|const pthread_rwlockattr_t*
|attr
|/* in */
|
```c
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
~~~
Using Read-Write Locks
To lock the resource for reading, use pthread_rwlock_rdlock
. To lock it for writing, use pthread_rwlock_wrlock
. After accessing the resource, unlock it with pthread_rwlock_unlock
.
```c
pthread_rwlock_rdlock(&rwlock);
// Reading critical section
pthread_rwlock_unlock(&rwlock);
pthread_rwlock_wrlock(&rwlock);
// Writing critical section
pthread_rwlock_unlock(&rwlock);
~~~