執行緒零碎知識總結
在啟動程式時,產生的程序只有單條執行緒。而建立執行緒時,每個執行緒都有一個屬於自己的大小固定的執行緒棧。
通過int pthread_create(pthread_t* thread,const pthread_attr_t* attr,void*(*start)(void*),void* arg);可以建立一條新執行緒。返回0表示成功,正整數表示錯誤。
執行緒ID:
每個執行緒都會有一個唯一的標識,可以通過pthread_t pthread_self(void);來獲取自己的執行緒ID。
通過pthread_equal(pthread_t t1,pthread_t t2)檢查ID是否相同,返回正整數表示相同。
執行緒的分離:
當不需要關心執行緒的返回狀態,只希望系統線上程終止後自動清理,可以呼叫pthread_detach(pthread_t thread)傳入指定執行緒的識別符號,將執行緒標記為分離狀態。
pthread_detach(pthread_self())可以自行分離,分離後就再也無法回到可連線狀態了。
連線已終止的執行緒
函式pthread_join(pthread_t thread,void** retval)等待由thread標識的執行緒終止,retval儲存返回值的拷貝。需要注意的是,如果向pthread_join()傳入一個之前已經連線過的執行緒ID,將會導致無法預知的行為,因為執行緒ID會被重用。此外,如果執行緒並未分離,則必須進行連線,否則將產生殭屍執行緒,殭屍執行緒如果積累過多,將再也無法建立新執行緒。
終止執行緒:
執行緒執行函式裡執行return,返回指定值。
執行緒呼叫pthread_exit(void* retval);retval指定了執行緒的返回值,但指向內容不能分配線上程棧中,因為執行緒終止後將無法確認執行緒棧的內容是否有效(系統可能將這部分割槽域分配給另一個執行緒棧使用 )如果主執行緒呼叫了pthread_exit(),那麼其他執行緒將繼續執行。
呼叫pthread_cancel()
任意執行緒呼叫exit()或者主執行緒執行return語句,會導致程序中所有執行緒立即終止。
執行緒同步:互斥量和條件變數
互斥量:多執行緒程式設計中需要注意的是多個執行緒不會同時修改同一個變數,不會讀取一個正在由其他執行緒修改的變數。為了避免此類問題,必須使用互斥量來確保同時僅有一個執行緒可以訪問共享資源。
互斥量有兩種狀態:已鎖定locked和未鎖定unlocked。任何時候,至多隻能有一個執行緒可以鎖定該互斥量。試圖對已經鎖定的某一互斥量再次加鎖,會出現執行緒阻塞直到獲得鎖或者報錯。
靜態分配互斥量:pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
加鎖:int pthread_mutex_lock(pthread_mutex_t* mutex);如果呼叫加鎖的執行緒本身就已經鎖了互斥量,可能會導致執行緒陷入死鎖或者呼叫失敗返回EDEADLK錯誤。
解鎖: int pthread_mutex_unlock(pthread_mutex_t* mutex);對處於未鎖定狀態的互斥量進行解鎖或者解鎖由其他執行緒鎖定的互斥量將會出錯。
動態初始化互斥量:int pthread_mutex_init(pthread_mutex_t* mutex,const pthread_mutexattr_t* attr);當不再需要互斥量後,使用pthread_mutex_destroy()將其銷燬。
條件變數:允許一個執行緒在某個共享資源狀態變化時通知其他執行緒,並讓其他執行緒阻塞直到接受到通知。主要操作是傳送訊號signal(通知別的執行緒,共享資源狀態改變)和等待wait(阻塞直到通知到達)。
靜態分配條件變數:pthread_cond_t cond = PTHREAD_COND_INITIALIZER
int pthread_cond_signal(pthread_cond_t* cond);只確保喚醒至少一條遭到阻塞的執行緒
int pthread_cond_broadcast(pthread_cond_t* cond);喚醒所有遭到阻塞的執行緒
int pthread_cond_wait(pthread_cond_t* cond,pthread_mutex_t* mutex)阻塞等待;
由動態分配的條件變數:
int pthread_cond_init(pthread_cond_t* cond,const pthread_condattr_t* attr);
int pthread_cond_destroy(pthread_cond_t* cond);
執行緒安全:
若函式可以同時被多個執行緒安全呼叫,那麼這是執行緒安全函式,反之不是。
實現執行緒安全的方式:將函式和互斥量關聯使用,這種方法意味著同時只有一個執行緒執行函式。另一種是確認函式中哪些部分使用了共享變數,在臨界區關聯互斥量。
一次性初始化
int pthread_once(pthread_once_t* once_control,void(*init)(void));確保無論呼叫了多少次,只會執行一次由init指向的函式
執行緒與程序
執行緒間的資料共享很簡單共享相同的地址空間,而程序間的資料共享需要建立共享記憶體或者使用管道之類的
建立執行緒要快於建立程序,執行緒間的上下文切換消耗時間要比程序短
多執行緒程式設計需要關注執行緒安全,多程序不需。
執行緒與exec()
若有任一執行緒呼叫exec()函式之一,呼叫程式將會被完全替換,除了呼叫的執行緒外,其餘的執行緒,互斥量,條件變數都會消失。且呼叫執行緒在呼叫exec()之後的執行緒ID是不確定的。
執行緒與fork()
當多執行緒程序呼叫fork(),只會將發起呼叫的執行緒複製到子程序中,其他執行緒均在子程序中消失。全域性變數的狀態,互斥量,條件變數之類都會在子程序中得以保留。在多執行緒程式中呼叫fork()後緊跟著對exec()呼叫