吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

什么是線程安全?如何理解線程安全?

冬至子 ? 來源:Linux大陸 ? 作者:LinuxZn ? 2023-05-30 14:33 ? 次閱讀

線程安全

在多線程編程中,線程安全是必須要考慮的因素。

什么是線程安全?

在多線程環境中,多個線程在同一時刻對同一份資源進行寫操作時,不會出現數據不一致。反之,則是線程非安全的。

線程安全是程序設計中的術語,指某個函數、函數庫在多線程環境中被調用時,能夠正確地處理多個線程之間的公用變量,使程序功能正確完成。

為了確保在多線程環境中的線程安全,就要確保數據的一致性。確保線程安全的幾種方法:

使用互斥鎖

一個線程,如果需要訪問公共資源,需要獲得互斥鎖并對其加鎖,資源在在鎖定過程中,如果其它線程對其進行訪問,也需要獲得互斥鎖,如果獲取不到,線程只能進行阻塞,直到獲得該鎖的線程解鎖。

#include 

int increment_counter(void)
{
 static int counter = 0;
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

 pthread_mutex_lock(&mutex);
 
 // only allow one thread to increment at a time
 ++counter;
 // store value before any other threads increment it further
 int result = counter; 

 pthread_mutex_unlock(&mutex);
 
 return result;
}

這個函數是線程安全的,可以在多個線程中被調用。

使用原子操作

上面的例子中,使用一個 互斥鎖來保護一次簡單的增量操作顯然過于昂貴,我們可以使用一些專門的原子操作API函數來替代。如上述例子,c++11中的原子變量提供了一個可使此函數既線程安全又可重入(而且還更簡潔)的替代方案:

#include 

int increment_counter(void)
{
 static std::atomic<int> counter(0);
 
 // increment is guaranteed to be done atomically
 int result = ++counter;

 return result;
}

Linux內核中原子整形操作:

#include 

int increment_counter(void)
{
 atomic_t counter = ATOMIC_INIT(0);
 
 // increment is guaranteed to be done atomically
 atomic_inc(&counter);
 int result = counter;

 return result;
}

什么是原子操作?

從字面上簡單理解,原子是一種很微小的粒子;原子操作是不能再進一步細分的操作。

從上面互斥鎖的例子來看,在線程層面,線程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:一個函數打開某個文件并讀入數據。這個函數是可重入的,因為它的多個實例同時執行不會造成沖突;但它不是線程安全的,因為在它讀入文件時可能有別的線程正在修改該文件,為了線程安全必須對文件加“同步鎖”。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 編譯器
    +關注

    關注

    1

    文章

    1642

    瀏覽量

    49284
  • C++語言
    +關注

    關注

    0

    文章

    147

    瀏覽量

    7027
  • LINUX內核
    +關注

    關注

    1

    文章

    316

    瀏覽量

    21742
收藏 人收藏

    評論

    相關推薦

    不同創建線程安全Set的方式

    線程安全的問題,真的算是老生常談了。這幾天看到一個 HashSet 線程安全的騷操作,在這里分享給大家。 在本文中,我們將分享如何構造線程
    的頭像 發表于 09-25 14:20 ?714次閱讀

    調用非安全線程的dll的問題

    在調用非線程安全的dll時,是不是要選擇在UI線程中運行?是不是還必須用不可重入的子VI封裝一下?上述的兩步是不是都要做?這些問題不是很清楚,還請各位大神指點一下
    發表于 03-14 21:13

    XC32源碼和字符串線程安全

    我正在嘗試我的項目的FrReTOS遷移,我想了解哪些字符串處理函數是線程安全的,或者不是線程安全的。特別是,我想看看StrudStruts,Strutk,還有一些其他的源代碼。但是,在
    發表于 11-26 16:03

    YYKit源碼線程安全計數器YYSentinel

    YYKit源碼探究(八十三) —— 線程安全計數器YYSentinel(一)
    發表于 04-28 16:57

    Linux下的線程安全是什么

    Linux下的線程安全原文結構有點亂線程安全:多個執行流對臨界資源進行爭搶訪問,而不會造成數據二義性和邏輯混亂,成這段代碼的過程是線程
    發表于 07-01 13:34

    什么是線程安全?如何去實現線程安全

    什么是線程安全?如何去實現線程安全?互斥實現的技術是什么?有哪些注意事項?同步實現的技術是什么?其操作流程有哪些?
    發表于 07-23 09:57

    請教大神rtthread中的ringbuff是線程安全的嗎

    最近想用輕量級的ringbuff,請教大神rtthread中的ringbuff是線程安全的嗎?
    發表于 07-29 10:44

    什么是線程安全

    線程安全的鏈表-隊列-棧,就是多線程同時操作(包括查找、添加、刪除等)鏈表、隊列或棧,無論如何操作,就是多線程同時操作(包括查找、添加、刪除等)鏈表、隊列或棧,無論如何操作,都不會產生
    發表于 11-17 11:16 ?1次下載

    解決線程安全問題技巧匯總

    線程,有時被稱為輕量級進程,是程序執行流的最小單元。一個標準的線程線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位
    發表于 12-01 13:42 ?1589次閱讀

    java的線程安全、單例模式、JVM內存結構

    線程安全就是多線程訪問時,采用了加鎖機制,當一個線程訪問類的某個數據時,進行保護,其他線程不能進行訪問直到該
    發表于 03-12 10:30 ?0次下載

    什么是線程安全 如何實現線程安全代碼

    相信有很多同學在面對多線程代碼時都會望而生畏,認為多線程代碼就像一頭難以馴服的怪獸,你制服不了這頭怪獸它就會反過來吞噬你。
    的頭像 發表于 05-17 12:45 ?1664次閱讀

    如何理解線程安全

    本次分享線程安全的基礎知識。
    的頭像 發表于 05-08 15:03 ?879次閱讀
    如何<b class='flag-5'>理解</b><b class='flag-5'>線程</b><b class='flag-5'>安全</b>?

    線程安全怎么辦

    線程安全一直是多線程開發中需要注意的地方,可以說,并發安全保證了所有的數據都安全。 1 線程
    的頭像 發表于 10-10 15:00 ?403次閱讀
    <b class='flag-5'>線程</b><b class='flag-5'>安全</b>怎么辦

    如何知道你的代碼是否線程安全

    在并發編程時,如果多個線程訪問同一資源,我們需要保證訪問的時候不會產生沖突,數據修改不會發生錯誤,這就是我們常說的 線程安全 。 那什么情況下,訪問數據時是安全的?什么情況下,訪問數據
    的頭像 發表于 11-01 11:42 ?767次閱讀
    如何知道你的代碼是否<b class='flag-5'>線程</b><b class='flag-5'>安全</b>

    redis多線程還能保證線程安全

    Redis是一種使用C語言編寫的高性能鍵值存儲系統,它是單線程的,因為使用了多路復用的方式來處理并發請求。這樣的實現方式帶來了很好的性能,但同時也引發了一些線程安全方面的問題。 在Redis中,由于
    的頭像 發表于 12-05 10:28 ?1899次閱讀
    开花财娱乐城| 百家乐视频游戏会员| bet365备用bd| 百家乐官网出庄几率| 百家乐赌博经历| 百家乐官网注册开户送现金| 百家乐真人游戏棋牌| 克拉克百家乐官网试玩| 圣保罗百家乐的玩法技巧和规则| 欢乐博百家乐官网娱乐城| 全讯网3344555| 百家乐官网视| 沂南县| 新花园百家乐的玩法技巧和规则 | 德州扑克软件| 百家乐博彩金| 百家乐官网玩法窍门| 赌场百家乐欺诈方法| 百家乐官网猜大小规则| 大发888官方 3000| 24山辅星水法分阴阳| 百家乐官网论坛白菜| 金榜百家乐的玩法技巧和规则 | 机器百家乐官网作弊| 免费百家乐统计工具| 百家乐官网排名| 必博网址| 百家乐77s| 缅甸百家乐官网赌场娱乐网规则 | 百家乐官网之三姐妹赌博机 | 属龙属虎合伙做生意吗| 镇巴县| 百家乐国际娱乐网| 菲彩百家乐官网的玩法技巧和规则| 百家乐官网统计概率| 大发888排行| 百家乐投注信用最好的| 百家乐官网大路图| 百家乐官网有没有绝| 全讯网3532888| 澳门百家乐十大缆|