大家好,我是LinuxZn。
本次分享線程安全的基礎知識。
線程安全
在多線程編程中,線程安全是必須要考慮的因素。
什么是線程安全?
在多線程環境中,多個線程在同一時刻對同一份資源進行寫操作時,不會出現數據不一致。反之,則是線程非安全的。
線程安全是程序設計中的術語,指某個函數、函數庫在多線程環境中被調用時,能夠正確地處理多個線程之間的公用變量,使程序功能正確完成。
為了確保在多線程環境中的線程安全,就要確保數據的一致性。確保線程安全的幾種方法:
使用互斥鎖
一個線程,如果需要訪問公共資源,需要獲得互斥鎖并對其加鎖,資源在在鎖定過程中,如果其它線程對其進行訪問,也需要獲得互斥鎖,如果獲取不到,線程只能進行阻塞,直到獲得該鎖的線程解鎖。關于互斥鎖的使用:Hello系列 | 多線程編程基礎!
例子(來源:維基百科):
#includeintincrement_counter(void) { staticintcounter=0; staticpthread_mutex_tmutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&mutex); //onlyallowonethreadtoincrementatatime ++counter; //storevaluebeforeanyotherthreadsincrementitfurther intresult=counter; pthread_mutex_unlock(&mutex); returnresult; }
這個函數是線程安全的,可以在多個線程中被調用。
使用原子操作
上面的例子中,使用一個 互斥鎖來保護一次簡單的增量操作顯然過于昂貴,我們可以使用一些專門的原子操作API函數來替代。如上述例子,c++11中的原子變量提供了一個可使此函數既線程安全又可重入(而且還更簡潔)的替代方案:
#includeintincrement_counter(void) { staticstd::atomic counter(0); //incrementisguaranteedtobedoneatomically intresult=++counter; returnresult; }
Linux內核中原子整形操作:
#includeintincrement_counter(void) { atomic_tcounter=ATOMIC_INIT(0); //incrementisguaranteedtobedoneatomically atomic_inc(&counter); intresult=counter; returnresult; }
什么是原子操作?
從字面上簡單理解,原子是一種很微小的粒子;原子操作是不能再進一步細分的操作。
從上面互斥鎖的例子來看,在線程層面,線程1和線程2同時調用了increment_counter函數,被 mutex 保護的操作是原子操作,lock、unlock及保護部分要整體順序運行,不可再進一步細分,作為一個原子存在 。
如果確定某個操作是原子的,并且有原子操作API函數可以使用,就不用為了去保護這個操作而加上會耗費昂貴性能開銷的鎖。
如,Linux內核原子整形操作 API 函數表(來源:正點原子) :
防止過度優化
線程安全的函數應該為每個調用它的線程分配專門的空間,把多個線程共享的變量正確對待(如,通知編譯器該變量為“易失(volatile)”型,阻止其進行一些不恰當的優化)。
線程安全函數與可重入函數?
先明確概念:
線程安全函數:能夠正確地處理多個線程之間的公用變量的函數。、
可重入函數:在任意時刻被中斷然后操作系統調度執行另一段代碼,這段代碼又使用了該副程序不會出錯。
可重入函數應當滿足條件:
不能含有靜態(全局)非常量數據。
不能返回靜態(全局)非常量數據的地址。
只能處理由調用者提供的數據。
不能依賴于單例模式資源的鎖。
調用(call)的函數也必需是可重入的。
可重入函數未必是線程安全的;線程安全函數未必是可重入的。
例子1:上述例子中的increment_counter函數是線程安全的,但是并不是可重入的。因為使用了互斥鎖,如果這個函數用在可重入的中斷處理程序中,如果在pthread_mutex_lock(&mutex)和pthread_mutex_unlock(&mutex)之間產生另一個調用函數increment_counter的中斷,則會第二次執行此函數,此時由于mutex已被lock,函數會在pthread_mutex_lock(&mutex)處阻塞,并且由于mutex沒有機會被unlock,阻塞會永遠持續下去。
例子2:一個函數打開某個文件并讀入數據。這個函數是可重入的,因為它的多個實例同時執行不會造成沖突;但它不是線程安全的,因為在它讀入文件時可能有別的線程正在修改該文件,為了線程安全必須對文件加“同步鎖”。
-
編程
+關注
關注
88文章
3614瀏覽量
93686 -
中斷
+關注
關注
5文章
898瀏覽量
41471 -
函數
+關注
關注
3文章
4327瀏覽量
62573 -
C++
+關注
關注
22文章
2108瀏覽量
73622 -
線程安全
+關注
關注
0文章
13瀏覽量
2458
原文標題:如何理解線程安全?
文章出處:【微信號:Linux大陸,微信公眾號:Linux大陸】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論