LINUX 執行緒基礎, 執行緒同步,執行緒控制
阿新 • • 發佈:2019-01-26
一 執行緒基礎
1)執行緒全稱控制執行緒
2)多執行緒的優勢:
a) 比程序方便,可以共享相同的記憶體空間及檔案描述符
b) 可以用於多個任務,而這些任務如果用單程序來實現是序列,
在多執行緒裡面由於CPU的排程可以實現穿插執行
c) 用於互動程式,將使用者輸入輸出與其他部分分開,優化效能
3)如何知道系統是否多執行緒pthread(POSIX執行緒)
a) #ifdef _POSIX_THREADS
b) sysconf(_SC_THREADS)
4)一個執行緒的資料結構
執行緒ID,一組暫存器,棧,排程優先順序,訊號遮蔽字,errno,私有資料
pthread_t 被實現為結構體這種才是可移植的
但linux 直接這樣定義了 typedef unsigned long int pthread_t;
5)執行緒id比較 pthread_equal(pthread_t ptd1, pthread_t ptd2)
獲得執行緒ID pthread_self(void)
6)執行緒建立 pthread_create(新執行緒的id,執行緒的屬性,執行緒執行地址,函式引數)
****新執行緒和主執行緒在建立後是競爭執行
****linux上是靠clone建立子程序來實現的,所以同一個程序裡面的執行緒獲取到pid可能不同(fedora8是相同的)
7)執行緒終止
如果任一執行緒呼叫了exit,_Exit,_exit,那麼整個程序就會終止
a)從啟動函式返回
b)被其他執行緒取消
c)執行緒呼叫pthread_exit
8)執行緒阻塞
pthread_join(pthread_t aim_ptd) 阻塞當前執行緒一直到目標執行緒退出 類似於程序控制裡面的wait
不能對分離狀態(設定為,或已經是detach狀態)的執行緒使用pthread_join,會返回失敗
只有一個執行緒可以對某個執行緒使用pthread_join
9)請求取消某個執行緒
pthread_cancel
10)登記執行緒退出清理函式,類似於atexit登記函式
pthread_cleanup_push(函式指標,引數)
除了pthread_exit,及響應取消請求而退出的時候執行清理函式,也可以呼叫pthread_cleanup_pop來執行函式
執行緒return退出是不會執行清理函式的
pthread_cleanup_pop(int execute) execute為0就不執行清理函式,只是刪除該處理函式,必須大於0才呼叫
11)分離執行緒 pthread_detach
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, THREAD_FUNCTION, arg);
可以設定執行緒為預設的detach,好讓作業系統線上程結束的時候,回收預設的資源
二 執行緒同步
原因: 現代計算機體系結構造成了資料不是順序一致來實現, 還有程式裡面的邏輯,不是原子操作而造成的
1)互斥量 本質上就是多放一塊全域性條件變數
pthread_mutex_t 訪問前加鎖,訪問完解鎖
使用步驟:
a)建立並初始化
靜態的pthread_mutex_t 賦值常量 PTHREAD_MUTEX_INITIALIZER
動態分配的pthread_mutext_t ,需要呼叫pthread_mutex_init初始化, pthread_mutex_destroy釋放
通過pthread_mutex_init可以指定互斥量的屬性,預設屬性輸入引數null
b)加鎖
pthread_mutex_lock,如果已經有鎖則阻塞到互斥變數解鎖
嘗試加鎖 pthread_mutex_trylock 加鎖不成功會馬上返回 EBUSY
c)訪問資料
d)解鎖
pthread_mutex_unlock 解鎖
2)避免互斥量死鎖
產生的原因: 執行緒對同一個互斥量加鎖2次,執行緒本身會陷入死鎖, 多個互斥量被多個執行緒以相反的順序訪問的時候
3)讀寫鎖 又名 共享-獨佔鎖
型別: 讀鎖 寫鎖
資料型別: pthread_rwlock_t
存在條件: 寫鎖一次最多一個執行緒佔據,讀鎖可以並行存在多個
加鎖條件:
a)當前鎖是寫鎖,所有其它新加鎖都會被阻塞
b)當前鎖是讀鎖,如果新加鎖是讀鎖,那麼可以獲得訪問許可權
c)當前鎖是讀鎖,如果新加鎖是寫鎖,那麼該鎖會被阻塞直到所有讀鎖解鎖。
****注意 為避免長期的讀鎖佔據寫的時間,但有寫鎖進來後,後續的讀鎖都會被拒絕掉
****適合讀的次數大於寫的次數的情況
初始化及釋放:
pthread_rwlock_init
pthread_rwlock_destroy
加鎖及解鎖
pthread_rwlock_rdlock
pthread_rwlock_wrlock
pthread_rwlock_unlock
嘗試加鎖
pthread_rwlock_tryrdlock
pthread_rwlock_trywrlock
4)條件變數
資料型別 pthread_cond_t
需要和互斥變數一起使用,受到互斥變數的保護
靜態初始化 賦值常量 PTHREAD_COND_INITIALIZER
動態初始化和釋放
pthread_cond_init pthread_cond_destroy
作用:
給多個執行緒提供了一個會合的場所,允許執行緒以無競爭的方式等待特定的條件發生
pthread_cond_wait
目的: 是通過互斥量的保護,講執行緒加入到某個等待條件的執行緒佇列裡面去
過程: 進入函式前,對互斥量加鎖
函式內部,將執行緒加入到佇列並解鎖
函式返回,再次對互斥量加鎖
pthread_cond_timedwait
同上,但是有個時間等待限制,時間是絕對值,即具體的時刻,資料型別 timespec
喚醒等待條件的執行緒:
pthread_cond_signal 喚醒等待某個條件的一個執行緒
pthread_cond_broadcast 喚醒等待某個條件的所有執行緒
學習條件變數用法的2個例子
http://www.cnblogs.com/yuallen/archive/2010/05/18/1738139.html
http://www.cnblogs.com/hnrainll/archive/2011/05/01/2033903.html
三 執行緒控制
1)執行緒屬性
a)資料型別 pthread_attr_t
b)初始化及釋放屬性結構 pthread_attr_init pthread_attr_destroy
c)獲取或設定執行緒分離狀態 pthread_attr_setdetachstate pthread_attr_getdetachstate
有2種可選的狀態值:
PTHREAD_CREATE_DETACHED 分離狀態
PTHREAD_CREATE_JOINABLE 正常狀態,可以使用pthread_join來獲取狀態
d)應該獲取pthread_atr_destroy的返回值,因為使用pthread_attr_init初始化的時候可能分配有記憶體,如果釋放記憶體失敗的話,
會造成記憶體洩漏
e)控制執行緒棧的空間的大小
需求:多個執行緒的棧空間累計超過了程序的可用虛擬地址空間
執行緒呼叫函式的自動變數很多,或者遞迴很深
1)管理stackaddr執行緒屬性,管理stacksize執行緒屬性
pthread_attr_getstack
pthread_attr_setstack
2)獲取或設定執行緒棧的大小
pthread_attr_setstacksize 系統幫助分配記憶體,自己不用管
pthread_attr_getstacksize
3)執行緒棧的保護
預設大小為巨集PAGESIZE,但修改了棧屬性後,這個值就會變成0
pthread_attr_getguardsize
pthread_attr_setguardsize
f)執行緒屬性-併發度
pthread_attr_setconcurency
pthread_attr_getconcurency
2)實現同步的3種方式中的物件的屬性
a)互斥量屬性 pthread_mutexattr_t
1)初始化及釋放 pthread_mutexattr_init pthread_mutexattr_destroy
2)程序共享屬性
獲取與設定共享屬性 pthread_mutexattr_getpshared pthread_mutexattr_setpshared
PTHREAD_PROCESS_PRIVAE 程序內的多個執行緒可以訪問同一個同步物件
PTHREAD_PROCESS_SHARED 多個程序可以共享同一塊記憶體區域 記憶體共享技術
b)互斥量型別屬性
PTHREAD_MUTEX_NORMAL 標準的互斥量型別,不做錯誤檢查或死鎖檢查
PTHREAD_MUTEX_DEFAULT 依賴於作業系統提供到其他型別的對映
PTHREAD_MUTEX_ERRORCHECK 提供錯誤檢查
PTHREAD_MUTEX_RECURSIVE 允許多次加鎖,但是需要解鎖對應次數 tmd,這個型別叫做遞迴鎖
獲取與設定互斥量型別屬性
pthread_mutexattr_gettype pthread_mutexattr_settype
c)讀寫鎖屬性 pthread_rwlockattr_t
只支援程序共享屬性
d)條件變數屬性pthread_condattr_t
只支援程序共享屬性
四 執行緒重入
1)執行緒安全:如果一個函式同一時刻可以被多個執行緒安全地呼叫
2)系統是否支援執行緒安全函式 sysconf(_POSIX_THREAD_SAFE_FUNCTIONS)
3)非同步-訊號安全:如果函式對非同步訊號處理程式的重入是安全的
4)鎖檔案的3個函式
flockfile ftrylockfile funlockfile
該鎖是遞迴鎖
5)確保函式在程序裡面只被呼叫一次
pthread_once_t var = PTHREAD_ONCE_INIT;
pthread_once(&var, function);
五 執行緒私有資料
1)需要的資料型別: pthread_key_t
2)建立私有資料的步驟
pthread_key_t key;
a)pthread_key_create(&key, 清理函式地址) 一般通過pthread_once確保函式只被執行一次,變數只被初始化一次
b)char* addr = pthread_getspecific(&key)
c)為addr分配記憶體 malloc
d)pthread_setspecific(&key, addr);
e)pthread_key_delete刪除key
f)執行緒退出,執行清理函式地址
六 執行緒取消
1)執行緒可以被設定為是否可取消
pthread_setcancelstate(int state, int* oldstate)
2)pthread_cancel只是一個申請,只有執行緒到達了取消點才會取消.
3)延遲取消pthread_testcancel, 適合於沒有取消點的函式
4)設定取消的型別pthread_setcanceltype
七 執行緒與IO
pread,pwrite 原子io操作
八 執行緒與訊號
每個執行緒有自己的訊號遮蔽字,但是他們共享
1)相同的訊號處理函式 2)該訊號與某函式的繫結,一個訊號繫結到某個函式,這個被所有執行緒共享, 他們只能看到一個
多個執行緒公用程序的訊號遮蔽機制,除了2種情況以外:
硬體故障的訊號與計時器超時的訊號,只遞送給某個執行緒,其它的訊號會發送給所有執行緒
pthread_sigmask
sigwait 等待訊號傳送. 一般操作需要先阻塞訊號,sigwait呼叫會取消訊號的阻塞狀態,直到新訊號到來
pthread_kill
sigwait(sigset_t*, int* signo)
sigwait的引數2表示捕獲到的訊號值
九 執行緒與fork
pthread_atfork,理論內容相當多,過濾掉
十 同一程序的所有執行緒共享同一個計時器
十一 同一程序的所有執行緒共享相同的檔案描述符
1)執行緒全稱控制執行緒
2)多執行緒的優勢:
a) 比程序方便,可以共享相同的記憶體空間及檔案描述符
b) 可以用於多個任務,而這些任務如果用單程序來實現是序列,
在多執行緒裡面由於CPU的排程可以實現穿插執行
c) 用於互動程式,將使用者輸入輸出與其他部分分開,優化效能
3)如何知道系統是否多執行緒pthread(POSIX執行緒)
a) #ifdef _POSIX_THREADS
b) sysconf(_SC_THREADS)
4)一個執行緒的資料結構
執行緒ID,一組暫存器,棧,排程優先順序,訊號遮蔽字,errno,私有資料
pthread_t 被實現為結構體這種才是可移植的
但linux 直接這樣定義了 typedef unsigned long int pthread_t;
5)執行緒id比較 pthread_equal(pthread_t ptd1, pthread_t ptd2)
獲得執行緒ID pthread_self(void)
6)執行緒建立 pthread_create(新執行緒的id,執行緒的屬性,執行緒執行地址,函式引數)
****新執行緒和主執行緒在建立後是競爭執行
****linux上是靠clone建立子程序來實現的,所以同一個程序裡面的執行緒獲取到pid可能不同(fedora8是相同的)
7)執行緒終止
如果任一執行緒呼叫了exit,_Exit,_exit,那麼整個程序就會終止
a)從啟動函式返回
b)被其他執行緒取消
c)執行緒呼叫pthread_exit
8)執行緒阻塞
pthread_join(pthread_t aim_ptd) 阻塞當前執行緒一直到目標執行緒退出 類似於程序控制裡面的wait
不能對分離狀態(設定為,或已經是detach狀態)的執行緒使用pthread_join,會返回失敗
只有一個執行緒可以對某個執行緒使用pthread_join
9)請求取消某個執行緒
pthread_cancel
10)登記執行緒退出清理函式,類似於atexit登記函式
pthread_cleanup_push(函式指標,引數)
除了pthread_exit,及響應取消請求而退出的時候執行清理函式,也可以呼叫pthread_cleanup_pop來執行函式
執行緒return退出是不會執行清理函式的
pthread_cleanup_pop(int execute) execute為0就不執行清理函式,只是刪除該處理函式,必須大於0才呼叫
11)分離執行緒 pthread_detach
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, THREAD_FUNCTION, arg);
可以設定執行緒為預設的detach,好讓作業系統線上程結束的時候,回收預設的資源
二 執行緒同步
原因: 現代計算機體系結構造成了資料不是順序一致來實現, 還有程式裡面的邏輯,不是原子操作而造成的
1)互斥量 本質上就是多放一塊全域性條件變數
pthread_mutex_t 訪問前加鎖,訪問完解鎖
使用步驟:
a)建立並初始化
靜態的pthread_mutex_t 賦值常量 PTHREAD_MUTEX_INITIALIZER
動態分配的pthread_mutext_t ,需要呼叫pthread_mutex_init初始化, pthread_mutex_destroy釋放
通過pthread_mutex_init可以指定互斥量的屬性,預設屬性輸入引數null
b)加鎖
pthread_mutex_lock,如果已經有鎖則阻塞到互斥變數解鎖
嘗試加鎖 pthread_mutex_trylock 加鎖不成功會馬上返回 EBUSY
c)訪問資料
d)解鎖
pthread_mutex_unlock 解鎖
2)避免互斥量死鎖
產生的原因: 執行緒對同一個互斥量加鎖2次,執行緒本身會陷入死鎖, 多個互斥量被多個執行緒以相反的順序訪問的時候
3)讀寫鎖 又名 共享-獨佔鎖
型別: 讀鎖 寫鎖
資料型別: pthread_rwlock_t
存在條件: 寫鎖一次最多一個執行緒佔據,讀鎖可以並行存在多個
加鎖條件:
a)當前鎖是寫鎖,所有其它新加鎖都會被阻塞
b)當前鎖是讀鎖,如果新加鎖是讀鎖,那麼可以獲得訪問許可權
c)當前鎖是讀鎖,如果新加鎖是寫鎖,那麼該鎖會被阻塞直到所有讀鎖解鎖。
****注意 為避免長期的讀鎖佔據寫的時間,但有寫鎖進來後,後續的讀鎖都會被拒絕掉
****適合讀的次數大於寫的次數的情況
初始化及釋放:
pthread_rwlock_init
pthread_rwlock_destroy
加鎖及解鎖
pthread_rwlock_rdlock
pthread_rwlock_wrlock
pthread_rwlock_unlock
嘗試加鎖
pthread_rwlock_tryrdlock
pthread_rwlock_trywrlock
4)條件變數
資料型別 pthread_cond_t
需要和互斥變數一起使用,受到互斥變數的保護
靜態初始化 賦值常量 PTHREAD_COND_INITIALIZER
動態初始化和釋放
pthread_cond_init pthread_cond_destroy
作用:
給多個執行緒提供了一個會合的場所,允許執行緒以無競爭的方式等待特定的條件發生
pthread_cond_wait
目的: 是通過互斥量的保護,講執行緒加入到某個等待條件的執行緒佇列裡面去
過程: 進入函式前,對互斥量加鎖
函式內部,將執行緒加入到佇列並解鎖
函式返回,再次對互斥量加鎖
pthread_cond_timedwait
同上,但是有個時間等待限制,時間是絕對值,即具體的時刻,資料型別 timespec
喚醒等待條件的執行緒:
pthread_cond_signal 喚醒等待某個條件的一個執行緒
pthread_cond_broadcast 喚醒等待某個條件的所有執行緒
學習條件變數用法的2個例子
http://www.cnblogs.com/yuallen/archive/2010/05/18/1738139.html
http://www.cnblogs.com/hnrainll/archive/2011/05/01/2033903.html
三 執行緒控制
1)執行緒屬性
a)資料型別 pthread_attr_t
b)初始化及釋放屬性結構 pthread_attr_init pthread_attr_destroy
c)獲取或設定執行緒分離狀態 pthread_attr_setdetachstate pthread_attr_getdetachstate
有2種可選的狀態值:
PTHREAD_CREATE_DETACHED 分離狀態
PTHREAD_CREATE_JOINABLE 正常狀態,可以使用pthread_join來獲取狀態
d)應該獲取pthread_atr_destroy的返回值,因為使用pthread_attr_init初始化的時候可能分配有記憶體,如果釋放記憶體失敗的話,
會造成記憶體洩漏
e)控制執行緒棧的空間的大小
需求:多個執行緒的棧空間累計超過了程序的可用虛擬地址空間
執行緒呼叫函式的自動變數很多,或者遞迴很深
1)管理stackaddr執行緒屬性,管理stacksize執行緒屬性
pthread_attr_getstack
pthread_attr_setstack
2)獲取或設定執行緒棧的大小
pthread_attr_setstacksize 系統幫助分配記憶體,自己不用管
pthread_attr_getstacksize
3)執行緒棧的保護
預設大小為巨集PAGESIZE,但修改了棧屬性後,這個值就會變成0
pthread_attr_getguardsize
pthread_attr_setguardsize
f)執行緒屬性-併發度
pthread_attr_setconcurency
pthread_attr_getconcurency
2)實現同步的3種方式中的物件的屬性
a)互斥量屬性 pthread_mutexattr_t
1)初始化及釋放 pthread_mutexattr_init pthread_mutexattr_destroy
2)程序共享屬性
獲取與設定共享屬性 pthread_mutexattr_getpshared pthread_mutexattr_setpshared
PTHREAD_PROCESS_PRIVAE 程序內的多個執行緒可以訪問同一個同步物件
PTHREAD_PROCESS_SHARED 多個程序可以共享同一塊記憶體區域 記憶體共享技術
b)互斥量型別屬性
PTHREAD_MUTEX_NORMAL 標準的互斥量型別,不做錯誤檢查或死鎖檢查
PTHREAD_MUTEX_DEFAULT 依賴於作業系統提供到其他型別的對映
PTHREAD_MUTEX_ERRORCHECK 提供錯誤檢查
PTHREAD_MUTEX_RECURSIVE 允許多次加鎖,但是需要解鎖對應次數 tmd,這個型別叫做遞迴鎖
獲取與設定互斥量型別屬性
pthread_mutexattr_gettype pthread_mutexattr_settype
c)讀寫鎖屬性 pthread_rwlockattr_t
只支援程序共享屬性
d)條件變數屬性pthread_condattr_t
只支援程序共享屬性
四 執行緒重入
1)執行緒安全:如果一個函式同一時刻可以被多個執行緒安全地呼叫
2)系統是否支援執行緒安全函式 sysconf(_POSIX_THREAD_SAFE_FUNCTIONS)
3)非同步-訊號安全:如果函式對非同步訊號處理程式的重入是安全的
4)鎖檔案的3個函式
flockfile ftrylockfile funlockfile
該鎖是遞迴鎖
5)確保函式在程序裡面只被呼叫一次
pthread_once_t var = PTHREAD_ONCE_INIT;
pthread_once(&var, function);
五 執行緒私有資料
1)需要的資料型別: pthread_key_t
2)建立私有資料的步驟
pthread_key_t key;
a)pthread_key_create(&key, 清理函式地址) 一般通過pthread_once確保函式只被執行一次,變數只被初始化一次
b)char* addr = pthread_getspecific(&key)
c)為addr分配記憶體 malloc
d)pthread_setspecific(&key, addr);
e)pthread_key_delete刪除key
f)執行緒退出,執行清理函式地址
六 執行緒取消
1)執行緒可以被設定為是否可取消
pthread_setcancelstate(int state, int* oldstate)
2)pthread_cancel只是一個申請,只有執行緒到達了取消點才會取消.
3)延遲取消pthread_testcancel, 適合於沒有取消點的函式
4)設定取消的型別pthread_setcanceltype
七 執行緒與IO
pread,pwrite 原子io操作
八 執行緒與訊號
每個執行緒有自己的訊號遮蔽字,但是他們共享
1)相同的訊號處理函式 2)該訊號與某函式的繫結,一個訊號繫結到某個函式,這個被所有執行緒共享, 他們只能看到一個
多個執行緒公用程序的訊號遮蔽機制,除了2種情況以外:
硬體故障的訊號與計時器超時的訊號,只遞送給某個執行緒,其它的訊號會發送給所有執行緒
pthread_sigmask
sigwait 等待訊號傳送. 一般操作需要先阻塞訊號,sigwait呼叫會取消訊號的阻塞狀態,直到新訊號到來
pthread_kill
sigwait(sigset_t*, int* signo)
sigwait的引數2表示捕獲到的訊號值
九 執行緒與fork
pthread_atfork,理論內容相當多,過濾掉
十 同一程序的所有執行緒共享同一個計時器
十一 同一程序的所有執行緒共享相同的檔案描述符