Try   HackMD

2021q1 Homework4 (quiz4)

contributed by < Shanola >

測驗 1

POSIX Thread (pthread) API 認識

透過 pthread 可以實現並行化的程式,對於多核或多處理器的系統中可以平行化或分散式執行,進而提高程式效能。相較於透過 forking 來產生的行程不必再配置記憶空間而是共享一個行程的資源。

Thread(執行緒) 的操作有 建立 終止 同步 排程 資料管理 行程互動

  • pthread_create() 建立新的執行緒,成功時回傳 0,反之回傳錯誤值。

    ​​​​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() 的參數 retval 可以用在 pthread_join()

  • pthread_cancel() 取消執行緒,成功時回傳 0,反之錯誤值。

    ​​​​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() 決定,具有兩種 states:

    • enable(預設) - PTHREAD_CANCEL_ENABLE
    • disable - PTHREAD_CANCEL_DISABLE

    收到 cancellation request 的執行緒狀態若為 disable,會 block 直到狀態改為 enable。
    當 cancellation 發生後,type 由 pthread_setcanceltype() 決定,具有兩種 types:

    • deferred(預設) - PTHREAD_CANCEL_DEFFERED
      意思是收到取消請求的執行緒會等到呼叫下一個 function (cancellation point) 才會被 canceled。
    • asynchronous - PTHREAD_CANCEL_ASYNCHRONOUS

    呼叫 pthread_testcancel() 可以給執行緒一個 cancellation point,讓執行可以趕緊回應 cancellation request,如果執行緒的 state 為 disable 或沒有 request,則這個函式不會有效果。

  • pthread_join() 等待執行緒終止,將其合併回行程,成功時回傳 0,反之錯誤值。

    ​​​​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,反之錯誤值。

    ​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()pthread_mutex_unlock() 包住想要鎖住的程式,建立互斥鎖的目的是限制執行緒同時訪問相同資源,避免預期之外的結果(race conditions)。當鎖已經被一個執行緒 locked,其他想要 lock 該鎖的執行緒會被 blocked 直到鎖可以被使用。
    pthread_mutex_destory()可以摧毀鎖,摧毀後的鎖指向的值是 undefined,若要使用需要再次 pthread_mutex_init()
    摧毀 unlock 的鎖是安全的,摧毀 locked 或有執行緒在嘗試 lock 或是鎖被其他執行緒用在 pthread_cond_timedwaitpthread_cond_wait 時的結果是 undefined behavior。

  • pthread_cond_t Condition variable 相關的函式

    ​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() 來建立或摧毀 condition variable,後者是用來等待或稍後處理某些事情,其機制是讓執行緒暫停或放棄使用處理器直到某些條件達成,它總是搭配 mutex 使用以避免 deadlock 發生。
    呼叫 pthread_cond_wait() / pthread_cond_timedwait() 的執行緒會 release mutex(這將使得其他執行緒得以取得鎖來行操作),並 block 在 condition variable 上,直到呼叫 pthread_cond_broadcast() / pthread_cond_signal() 後才會被喚醒。

  • pthread_condattr_t Condition variable attributes object

    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

    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() 會將 routine 丟到 clean-up handler 的 stack 的 top,並以 arg 作為參數傳入,透過 pthread_clean_pop() 則可移除 stack 的 top

tags: linux2021