# Threads Case Study: PThreads

## Creation

To represent the thread data structure, PThread supports a `pthread_t` data type in C.

```c
pthread_t aThread;
```

The data type contains an ID, execution state, and any other information that's relevant to the thread.

```c
int pthread_create(pthread_t *thread,
                   pthread_attr_t *attr,
                   void * (*start_routine)(void *),
                   void *arg);
```

### Attributes

Pthread attributes allow us to specify the stack size, scheduling policy, inheritance, joinablility, priority, and system process scope of the newly created pthread. If `NULL` is passed in, all these attributes will be instantiated with some default values. There are multiple API calls available to pthread attributes.

```c
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
pthread_attr_{set/get}{attribute}
```

### Detachable

In pthreads, the default behavior of thread creation is joinable. With joinable threads, the parent thread creates children threads and can join them at a later time. The parent thread will not terminate until the children threads have completed their execution and have been joined via the explicit join operation.

In the event of parent thread exits early and fails to terminate children threads properly, the children threads can become zombie threads and eat up memory because it is expecting to *join* the parent before releasing its resources. However, if we specify the thread to be detachable, the thread can continue execute and release its resource upon termination.

Here's an example of detached threads.

```c
#include <stdio.h>
#include <pthread.h>

void *foo(void *arg) {
    printf("Foobar!\n")
    pthread_exit(NULL);
}

int main(void) {
    int i;
    pthread_t tid;

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_create(NULL, &attr, foo, NULL);

    return 0;
}
```

## Mutexes

The mutex type is represented by the following construct.

```c
pthread_mutex_t my_mutex;
```

While the lock and unlock operation will have the following signature.

```c
int pthread_mutex_lock(pthread_mutex_t* mutex);
int pthread_mutex_unlock(pthread_mutex_t* mutex);
```

Here's an example of thread safe insertion to a list.

```c
list<int> my_list;
pthread_mutex_t m;

void safe_insert(int i) {
    pthread_mutex_lock(m);
    my_list.insert(i);
    pthread_mutex_unlock(m);
}
```

### Other Mutex Operations

Mutex needs to be initialized. The attribute specifies the mutex behavior when it is shared among processes.

```c
int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr);
```

We can also check a mutex and see if it is locked. If it is locked, the check function will return immediately instead of being blocked.

```c
int pthread_mutex_trylock(pthread_mutex_t* mutex);
```

Finally we need to destroy the mutex to free up memory.

```c
int pthread_mutex_destroy(pthread_mutex_t* mutex);
```

### Mutex Safety

* Shared data should always be access through a single mutex.
* Mutex scope must be visible to all threads.
* We should globally order locks. This is to ensure there is no deadlock in the operations.

## Condition Variables

The condition variable type is represented by the following construct.

```c
pthread_cond_t cond;
```

The wait operation takes two arguments, the condition and the mutex. A thread that is entering the wait operation will automatically release the mutex and place itself on the wait queue that's associated with the condition variable. When the thread is woken up, it will automatically re-acquire the mutex before exiting the wait operation.

```c
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);
```

Here are signal and broadcast operations.

```c
int pthread_cond_signal(pthread_cond_t* cond);
int pthread_cond_broadcast(pthread_cond_t* cond);
```

### Other Cond Operations

```c
int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* attr);
int pthread_cond_destroy(pthread_cond_t* cond);
```

### Cond Safety

* Do not forget to notify waiting threads.
* When in doubt, use broadcast.
* You do not need a mutex to signal or broadcast.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://calvinfeng.gitbook.io/omscs/cs8803/p2l3.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
