1. 程式人生 > 其它 >Linux多執行緒開發

Linux多執行緒開發

一、執行緒

概念

執行緒(thread)是一種允許應用程式併發執行多個任務的機制。

執行緒之間共享全域性資料區,以及堆區。

程序是CPU分配資源的最小單位,執行緒是作業系統排程執行的最小單位。

執行緒是輕量級程序(LWP: Light Weight Process),在Linux環境下,其本質仍是程序

檢視指定的程序的LWP號:ps -Lf pid

區別

程序間的資訊難以共享,需要通過程序間通訊來進行資訊互動

fork的代價較高,儘管已經使用了寫時複製,讀時共享技術;仍需要複製PCB資訊,如記憶體頁表,檔案描述符表等。

執行緒只需要將資料複製到共享變數(全域性或堆)中即可共享資訊。

建立執行緒比建立程序快10倍甚至更多。無需寫時複製,也無需複製頁表。

 NPTL,或稱為 Native Thread Library,是Linux執行緒的一個新實現,滿足了POSIX需求,提升了效能和穩定性。

檢視當前pthread版本庫:getconf GNU_LIBPTHREAD_VERSION

執行緒操作

預設main函式所在的執行緒為主執行緒,其餘為子執行緒。

#include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);     - 功能:建立一個子執行緒     - 引數:         - thread:傳出引數,執行緒建立成功後,子執行緒的執行緒ID被寫到該變數中。         - attr : 設定執行緒的屬性,一般使用預設值,NULL         - start_routine : 函式指標,這個函式是子執行緒需要處理的邏輯程式碼         - arg : 給第三個引數使用,傳參     - 返回值:         成功:0         失敗:返回錯誤號。這個錯誤號和之前errno不太一樣。         獲取錯誤號的資訊:  char * strerror(int errnum);   void pthread_exit(void *retval);     功能:終止一個執行緒,在哪個執行緒中呼叫,就表示終止哪個執行緒     引數:         retval:需要傳遞一個指標,作為一個返回值,可以在pthread_join()中獲取到。
pthread_t pthread_self(void);     功能:獲取當前的執行緒的執行緒ID
int pthread_equal(pthread_t t1, pthread_t t2);     功能:比較兩個執行緒ID是否相等     不同的作業系統,pthread_t型別的實現不一樣,有的是無符號的長整型,有的     是使用結構體去實現的。   #include <pthread.h> int pthread_join(pthread_t thread, void **retval);     - 功能:和一個已經終止的執行緒進行連線             回收子執行緒的資源             這個函式是阻塞函式,呼叫一次只能回收一個子執行緒             一般在主執行緒中使用     - 引數:         - thread:需要回收的子執行緒的ID         - retval: 接收子執行緒退出時的返回值     - 返回值:         0 : 成功         非0 : 失敗,返回的錯誤號   #include <pthread.h> int pthread_detach(pthread_t thread);     - 功能:分離一個執行緒。被分離的執行緒在終止的時候,會自動釋放資源返回給系統。         1.不能多次分離,會產生不可預料的行為。         2.不能去連線一個已經分離的執行緒,會報錯。     - 引數:需要分離的執行緒的ID     - 返回值:         成功:0         失敗:返回錯誤號   #include <pthread.h> int pthread_cancel(pthread_t thread);     - 功能:取消執行緒(讓執行緒終止)         取消某個執行緒,可以終止某個執行緒的執行,         但是並不是立馬終止,而是當子執行緒執行到一個取消點,執行緒才會終止。         取消點:系統規定好的一些系統呼叫,我們可以粗略的理解為從使用者區到核心區的切換,這個位置稱之為取消點。  

執行緒屬性

執行緒屬性型別 pthread_attr_t   int pthread_attr_init(pthread_attr_t *attr);     - 初始化執行緒屬性變數
int pthread_attr_destroy(pthread_attr_t *attr);     - 釋放執行緒屬性的資源
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);     - 獲取執行緒分離的狀態屬性
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);     - 設定執行緒分離的狀態屬性  

二、執行緒同步

概念

執行緒通過全域性變數來共享資訊,十分便捷;但也會導致問題,多個執行緒同時修改同一變數。

臨界區:訪問共享資源的程式碼片段,且為原子操作。

執行緒同步:一次只能有一個執行緒操作記憶體。

互斥量

互斥量(mutex,mutual exclusion)可以保證對共享資源的原子訪問(同時僅有一個執行緒訪問資源)

使用時:先加鎖,再訪問共享資源,最後解鎖

API介紹

互斥量的型別 pthread_mutex_t int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);     - 初始化互斥量     - 引數 :         - mutex : 需要初始化的互斥量變數         - attr : 互斥量相關的屬性,NULL     - restrict : C語言的修飾符,被修飾的指標,不能由另外的一個指標進行操作。         pthread_mutex_t *restrict mutex = xxx;         pthread_mutex_t * mutex1 = mutex;
int pthread_mutex_destroy(pthread_mutex_t *mutex);     - 釋放互斥量的資源
int pthread_mutex_lock(pthread_mutex_t *mutex);     - 加鎖,阻塞的,如果有一個執行緒加鎖了,那麼其他的執行緒只能阻塞等待
int pthread_mutex_trylock(pthread_mutex_t *mutex);     - 嘗試加鎖,如果加鎖失敗,不會阻塞,會直接返回。
int pthread_mutex_unlock(pthread_mutex_t *mutex);     - 解鎖   死鎖 多個程序在執行過程中,因爭奪共享資源而造成的一種互相等待的現象。 原因:忘記釋放鎖;重複加鎖;多執行緒多鎖,搶佔資源  

讀寫鎖

有時,我們希望共享讀,獨佔寫;這就是讀寫鎖的需求。

特點

  • 如果有其它執行緒讀資料,則允許其它執行緒執行讀操作,但不允許寫操作。
  • 如果有其它執行緒寫資料,則其它執行緒都不允許讀、寫操作。
  • 寫是獨佔的,寫的優先順序高。

API介紹

讀寫鎖的型別 pthread_rwlock_t int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

條件變數

條件變數的型別 pthread_cond_t int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);     - 等待,呼叫了該函式,執行緒會阻塞。 int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);     - 等待多長時間,呼叫了這個函式,執行緒會阻塞,直到指定的時間結束。 int pthread_cond_signal(pthread_cond_t *cond);     - 喚醒一個或者多個等待的執行緒 int pthread_cond_broadcast(pthread_cond_t *cond);     - 喚醒所有的等待的執行緒  

訊號量

訊號量的型別 sem_t int sem_init(sem_t *sem, int pshared, unsigned int value);     - 初始化訊號量     - 引數:         - sem : 訊號量變數的地址         - pshared : 0 用線上程間 ,非0 用在程序間         - value : 訊號量中的值
int sem_destroy(sem_t *sem);     - 釋放資源
int sem_wait(sem_t *sem);     - 對訊號量加鎖,呼叫一次對訊號量的值-1,如果值為0,就阻塞
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); int sem_post(sem_t *sem);     - 對訊號量解鎖,呼叫一次對訊號量的值+1
int sem_getvalue(sem_t *sem, int *sval);
sem_t psem; sem_t csem; init(psem, 0, 8); init(csem, 0, 0);
producer() {     sem_wait(&psem);     sem_post(&csem) }
customer() {     sem_wait(&csem);     sem_post(&psem) }