# 2021q1 Homework4 (quiz4)
contributed by < `Shanola` >
## 測驗 `1`
### POSIX Thread (pthread) API 認識
透過 pthread 可以實現並行化的程式,對於多核或多處理器的系統中可以平行化或分散式執行,進而提高程式效能。相較於透過 forking 來產生的行程不必再配置記憶空間而是共享一個行程的資源。
Thread(執行緒) 的操作有 **建立 終止 同步 排程 資料管理 行程互動**:
* [`pthread_create()`](https://man7.org/linux/man-pages/man3/pthread_create.3.html) 建立新的執行緒,成功時回傳 0,反之回傳錯誤值。
```cpp=
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
void pthread_exit(void *retval);
```
將執行緒終止的方式有幾種:
1. 在行程中呼叫 pthread_exit()
2. 在執行緒中 return
3. 在行程中呼叫 pthread_cancel()
4. 在行程中呼叫 exit() 或 return,這會終止所有 thread
透過傳入 [`pthread_exit()`](https://man7.org/linux/man-pages/man3/pthread_exit.3.html) 的參數 `retval` 可以用在 [`pthread_join()`](https://man7.org/linux/man-pages/man3/pthread_join.3.html)
* [`pthread_cancel()`](https://man7.org/linux/man-pages/man3/pthread_cancel.3.html) 取消執行緒,成功時回傳 0,反之錯誤值。
```cpp=
int pthread_cancel(pthread_t thread);
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
void pthread_testcancel(void);
```
而一個執行緒的 cancelability state 由 [`pthread_setcancelstate()`](https://man7.org/linux/man-pages/man3/pthread_setcancelstate.3.html) 決定,具有兩種 states:
- enable(預設) - PTHREAD_CANCEL_ENABLE
- disable - PTHREAD_CANCEL_DISABLE
收到 cancellation request 的執行緒狀態若為 disable,會 block 直到狀態改為 enable。
當 cancellation 發生後,type 由 [`pthread_setcanceltype()`](https://man7.org/linux/man-pages/man3/pthread_setcancelstate.3.html) 決定,具有兩種 types:
- deferred(預設) - PTHREAD_CANCEL_DEFFERED
意思是收到取消請求的執行緒會等到呼叫下一個 function (cancellation point) 才會被 canceled。
- asynchronous - PTHREAD_CANCEL_ASYNCHRONOUS
呼叫 [`pthread_testcancel()`](https://man7.org/linux/man-pages/man3/pthread_testcancel.3.html) 可以給執行緒一個 cancellation point,讓執行可以趕緊回應 cancellation request,如果執行緒的 state 為 disable 或沒有 request,則這個函式不會有效果。
* [`pthread_join()`](https://man7.org/linux/man-pages/man3/pthread_join.3.html) 等待執行緒終止,將其合併回行程,成功時回傳 0,反之錯誤值。
```cpp=
int pthread_join(pthread_t thread, void **retval);
```
只有 joinable 的執行緒可以使用這個函式,若 retval 不是 NULL,則 pthread_join 會複製該目標執行緒的 exit status 到 retval,譬如執行緒被 calceled,retval 指向的值會是 `PTHREAD_CANCELED`。
若有多個執行緒同時 join,results 未定義。
* `pthread_mutex_t` Mutex (互斥鎖) 相關的函式,成功時回傳 0,反之錯誤值。
```cpp=
pthread_mutex_t mutex;
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); /* equal to pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER */
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
```
透過 [`pthread_mutex_lock() / pthread_mutex_trylock()`](https://man7.org/linux/man-pages/man3/pthread_mutex_lock.3p.html) 及 [`pthread_mutex_unlock()`](https://man7.org/linux/man-pages/man3/pthread_mutex_unlock.3p.html) 包住想要鎖住的程式,建立互斥鎖的目的是限制執行緒同時訪問相同資源,避免預期之外的結果(race conditions)。當鎖已經被一個執行緒 locked,其他想要 lock 該鎖的執行緒會被 blocked 直到鎖可以被使用。
[`pthread_mutex_destory()`](https://man7.org/linux/man-pages/man3/pthread_mutex_destroy.3p.html)可以摧毀鎖,摧毀後的鎖指向的值是 undefined,若要使用需要再次 [`pthread_mutex_init()`](https://man7.org/linux/man-pages/man3/pthread_mutex_destroy.3p.html)。
摧毀 unlock 的鎖是安全的,摧毀 locked 或有執行緒在嘗試 lock 或是鎖被其他執行緒用在 `pthread_cond_timedwait` 或 `pthread_cond_wait` 時的結果是 undefined behavior。
* `pthread_cond_t` Condition variable 相關的函式
```cpp=
pthread_cond_t cond;
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); /* equal to pthread_cond_t cond = PTHREAD_COND_INITIALIZER */
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, thread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
```
透過 [`pthread_cond_init() / pthread_cond_destroy()`](https://man7.org/linux/man-pages/man3/pthread_cond_init.3p.html) 來建立或摧毀 condition variable,後者是用來等待或稍後處理某些事情,其機制是讓執行緒暫停或放棄使用處理器直到某些條件達成,它總是**搭配 mutex 使用**以避免 deadlock 發生。
呼叫 [`pthread_cond_wait() / pthread_cond_timedwait()`](https://man7.org/linux/man-pages/man3/pthread_cond_wait.3p.html) 的執行緒會 release mutex(這將使得其他執行緒得以取得鎖來行操作),並 block 在 condition variable 上,直到呼叫 [`pthread_cond_broadcast() / pthread_cond_signal()`](https://man7.org/linux/man-pages/man3/pthread_cond_broadcast.3p.html) 後才會被喚醒。
* `pthread_condattr_t` Condition variable attributes object
```cpp=
int pthread_condattr_destroy(pthread_condattr_t *attr);
int pthread_condattr_init(pthread_condattr_t *attr);
```
用來建立 condition variable attribute object,然後使用在 `pthread_cond_init()` 來建立 condition variables。
* Thread-cancellation clean-up handlers
```cpp=
void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);
```
**Clean-up handler** 可以使執行緒被 canceled 時自動執行的 function,譬如可以將已經 canceled (或其他情況) 的執行緒做 unlock,因為在執行緒如果在 locked 時被 canceled 了,會導致 pthread_join 一直 wait,除非把它 unlock。
[`pthread_cleanup_push()`](https://man7.org/linux/man-pages/man3/pthread_cleanup_push.3.html) 會將 `routine` 丟到 clean-up handler 的 stack 的 top,並以 `arg` 作為參數傳入,透過 [`pthread_clean_pop()`](https://man7.org/linux/man-pages/man3/pthread_cleanup_push.3.html) 則可移除 stack 的 top
###### tags: `linux2021`