當多個執行緒共享相同的記憶體時,需要確保每個執行緒看到一致的資料檢視,當多個執行緒同時去修改這片記憶體時,就可能出現偏差,得到與預期不符合的值。為啥需要同步,一件事情邏輯上一定是有序的,即使在併發環境下;而作業系統對於多執行緒不會自動幫我們序列化,所以需要我們通過作業系統提供的同步方式api,結合自己的業務邏輯,利用多執行緒提高效能的同時,保證業務邏輯的正確性。一般而言,linux下同步方式主要有4種,原子鎖,互斥量,讀寫鎖和條件變數。下面一一介紹幾種同步方式。
1. spinlock
1) 概念
spinlock是一種互斥結構,通過cpu提供的特殊的原子指令集合實現互斥地訪問乙個資源,需要硬體支援。乙個執行緒訪問資料未結束的時候,其他執行緒不得對同乙個資料進行訪問。
2) 實現
spinlock一般基於原子的read-modify-write操作實現。read-modify-write操作允許乙個cpu讀取乙個值,修改該值,並將修改完成的值回寫記憶體的三個操作作為乙個原子匯流排操作,因此需要cpu特殊支援。具體而言,通過test-and-set指令實現,從記憶體中讀取乙個值,然後和0比較,並且將記憶體中的值設定為1。
3) 相關函式
a) 原子操作
1 test_and_set(volatileint*addr, value)
2
這裡volatile修飾詞告訴編譯器從記憶體中獲取,保證正確性,避免從暫存器中讀取到不準確的值。
b) 設定鎖變數
1set_spinlock(lock_word)
213 }
c) 重置鎖變數
1reset_spinlock(lock_word)
2
2. mutex
1) 概念
與 spinlock作用相同,保證互斥地訪問乙個資源。
2) 相關函式
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
pthread_mutex_trylock()語義與pthread_mutex_lock()類似,不同的是在鎖已經被佔據時返回ebusy而不是掛起等待。
3) spinlock與mutex的區別
a) 作用範圍,mutex是核心物件,可以在多執行緒,多程序同步中使用;spinlock作用範圍僅限於本程序(鎖變數是程序內的),僅適用於多執行緒同步。
b) spinlock依賴於硬體的原子操作指令
c) 執行緒獲取spinlock失敗時,會採取迴圈等待的方式,此時執行緒處於執行狀態,cpu空轉;而獲取mutex失敗時,執行緒會掛起,執行緒處於wait狀態,不會被核心排程。
d) 由於3的特點,進入等待狀態或從等待狀態被喚醒,都涉及到cpu的上下文切換,而cpu切換是比較耗時的,一般需要25us。相對而言spinlock則沒有這樣的代價,效率更高。
e) 也由於3的特點,spinlock會空轉,導致浪費大量的cpu時間片,若使用者持有鎖時間長,導致空轉時間長,也得不償失。因此spinlock比較適合於「快拿快放」的使用場景。
3.讀寫鎖
1) 概念
spinlock和互斥量都是保證同一時刻只有乙個執行緒操作共享記憶體。互斥鎖要麼是加鎖狀態,要麼是不加鎖狀態,一次只有乙個執行緒可以對其加鎖。讀寫所可以有3種狀態,讀模式下加鎖狀態,寫模式下加鎖狀態,不加鎖狀態。相對於前兩者,讀寫鎖有更高的併發度,允許多個執行緒同時讀共享記憶體。
2) 相關函式
pthread_rwlock_rdlock(pthread_rwlock_t*); 讀鎖定
pthread_rwlock_tryrdlock(pthread_rwlock_t*); 非阻塞讀鎖定
pthread_rwlock_wrlock(pthread_rwlock_t*); 寫鎖定
pthread_rwlock_trywrlock(pthread_rwlock_t*); 非阻塞寫鎖定
pthread_rwlock_unlock(pthread_rwlock_t*); 釋放鎖
4. 條件變數
1) 概念
條件變數是另外一種同步機制,通過與互斥鎖配合使用,利用鎖保護條件變數,通過條件變數實現喚醒和等待的機制。通過這種方式,允許執行緒以無競爭的方式等待特定的條件發生
2) 相關函式
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); //等待條件發生。
3) 說明
呼叫pthread_cond_wait之前,需要執行緒獲取互斥量,呼叫者把互斥量傳遞給函式,函式把呼叫執行緒發到等待佇列上,然後對互斥量解鎖,這個操作是原子操作。當pthread_cond_wait返回時,互斥量會再次被鎖住,這個實現都在pthread_cond_wait函式中實現,不需要使用者邏輯介入。
Linux多執行緒同步的幾種方式
執行緒的最大特點是資源的共享性,但資源共享中的同步問題是多執行緒程式設計的難點。linux下提供了多種方式來處理執行緒同步,最常用的是互斥鎖 條件變數和訊號量。1 互斥鎖 mutex 通過鎖機制實現執行緒間的同步。同一時刻只允許乙個執行緒執行乙個關鍵部分的 int pthread mutex ini...
同步,多執行緒 ,多執行緒方式實現併發。
io請求幾乎不佔cpu的。同步請求相當於排隊買東西,乙個卡主了,其他的都結不了賬了。執行緒並不是越多越好,如果他特別多還不如同步高,所以對執行緒要有個限制,所以就出現了執行緒池,執行緒池在python3裡才有的,python2裡沒有的。建立程序的話是耗費很多資源的,建立執行緒是幾乎不耗費資源的。建立...
Linux多執行緒,執行緒同步
5 執行緒私有資料 程序內的所有執行緒共享程序的資料空間,因此全域性變數為所有執行緒所共有。但有時執行緒也需要儲存自己的私有資料,這時可以建立執行緒私有資料 thread specific date tsd 來解決。例如我們常見的變數 errno 它返回標準的出錯資訊。它顯然不能是乙個區域性變數,幾...