国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux——線程3|線程互斥和同步

這篇具有很好參考價值的文章主要介紹了Linux——線程3|線程互斥和同步。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

加鎖保護

我們上一篇提到過,多個線程執(zhí)行下面代碼可能會出錯,具體原因可查看上一篇Linux博客。

Linux——線程3|線程互斥和同步
Linux——線程3|線程互斥和同步

為避免這種錯誤的出現(xiàn),我們可采用加鎖保護。

互斥鎖

PTHREAD_MUTEX_INITIALIZER

Linux——線程3|線程互斥和同步

用pthread_mutex_t定義一把鎖。ptherad_mutex_init是對鎖進行初始化的函數(shù)。如果這把鎖是全局的并且是靜態(tài)定義的,我們可直接使用PTHREAD_MUTEX_INITIALIZER這樣的話宏進行初始化,用這種方式進行初始化不需要init和destroy。

在這里,這把鎖用來保護全局的tickets這一過程我們稱為訪問臨界資源時對臨界資源進行保護。

訪問臨界資源的代碼被稱作臨界區(qū),這里的臨界區(qū)是函數(shù)里面if語句大括號里包含的內容

Linux——線程3|線程互斥和同步

pthread_mutex_lock

Linux——線程3|線程互斥和同步

返回值成功返回0,失敗返回錯誤碼。

Linux——線程3|線程互斥和同步

pthread_mutex_lock是進行加鎖,出入的是剛才定義的鎖

加了鎖之后,每個線程都會進行加鎖,加鎖的特點是:任何一個時刻,只允許一個線程成功獲得這把鎖,其它沒有拿到鎖的線程進行阻塞等待,直到拿到鎖的線程把鎖給釋放掉,其它線程才能進來。

Linux——線程3|線程互斥和同步

加鎖之后,任何一個時刻,只允許一個線程執(zhí)行這部分代碼以及后面的解鎖。即加鎖后的代碼只允許一個線程去執(zhí)行,其它線程進行阻塞等待。

Linux——線程3|線程互斥和同步

pthread_mutex_unlock

pthread_mutex_unlock是用來進行解鎖的,返回值成功返回0,失敗返回錯誤碼。

Linux——線程3|線程互斥和同步
Linux——線程3|線程互斥和同步

若把解鎖寫在這里,當tickets為0時候,執(zhí)行break,此時直接退出while循環(huán),未經(jīng)過解鎖,其它線程無法會一直阻塞

Linux——線程3|線程互斥和同步

因此,我們需要修改加鎖位置,其中加鎖和解鎖之間的代碼稱為臨界區(qū),這里被共享訪問的tickets就是臨界資源。

Linux——線程3|線程互斥和同步

運行程序后,結果正確,但我們可以看到截圖里是一個進程在搶,這是因為當某個線程搶完票后,釋放了所,但該線程的優(yōu)先級可能很高,進而又被調度會又被執(zhí)行,

Linux——線程3|線程互斥和同步

我們讓程序執(zhí)行完后usleep一會

Linux——線程3|線程互斥和同步

此時可以獲得我們想要的結果

Linux——線程3|線程互斥和同步

加鎖的時候,一定要保證加鎖的力度,越小越好,越細越好。如這里,盡量不要像下圖這樣加解鎖,這段程序我們主要的核心還是tickets,這里我們可以把函數(shù)里面的打印語句,放到解鎖后面,

Linux——線程3|線程互斥和同步

ptherad_mutex_init

若我們不想定義全局鎖(全局變量的鎖),若我們在main函數(shù)定義了一把鎖,若要使用,就必須用pthread_mutex_init進行初始化。

第一個參數(shù),這把鎖的地址,第二個參數(shù),這把鎖的屬性,我們一般設為空。

返回值成功返回0,失敗返回錯誤碼。

Linux——線程3|線程互斥和同步

pthread_mutex_destory

當我們不要在main函數(shù)定義的鎖時,我們用pthread_mutex_destory

我們用局部的鎖,對多個線程進行加鎖

Linux——線程3|線程互斥和同步
Linux——線程3|線程互斥和同步
Linux——線程3|線程互斥和同步

進行一下小優(yōu)化

Linux——線程3|線程互斥和同步
Linux——線程3|線程互斥和同步

思考題

  1. 加了鎖之后,線程在臨界區(qū)中,是否會切換,會有問題嗎?

會切換,OS說了算,OS調度器決定是否切換。不會有問題,因為雖然被切換了,但是我們是持有鎖被切換的,所以其它搶票線程要執(zhí)行臨界區(qū)代碼,也必須先申請鎖,鎖它是無法申請成功的,因為鎖在被切走的進程身上,所以,也不會讓其它線程進入臨界區(qū),就保證了臨界區(qū)中數(shù)據(jù)一致性。當一個線程,不申請鎖,直接去訪問臨界資源,這種方式是錯誤的編碼方式。

  1. 原子性在哪里體現(xiàn)?

目前來說,在沒有持有鎖的線程看來,對該線程最有意義的情況只有倆種:1.前面的線程未持有鎖(什么都沒做)2.前面的線程釋放鎖(做完)。因為此時該線程可以申請鎖。

  1. 加鎖就是串行執(zhí)行了嗎?

是的,執(zhí)行臨界區(qū)代碼一定是串行的。

要訪問臨界資源,每一個線程都必須先申請鎖,前提是每一個線程都必須看到同一把鎖并且并且去訪問它,鎖本身就是一種共享資源。在上面代碼中,鎖保護了tickets,而誰又來保證鎖的安全呢?所以,為了保證鎖的安全,申請和釋放鎖必須是原子的。那么有如何保證原子性呢?我們繼續(xù)往下看,鎖是如何實現(xiàn)的。

互斥鎖的實現(xiàn)

swap或exchange指令是以一條匯編的方式,將內存和CPU內寄存器數(shù)據(jù)進行交換。

如果我們在匯編的角度,如果只有一條匯編語句,我們就人為該匯編語句的執(zhí)行是原子的。

加鎖和解鎖的代碼

lock相當于pthread_mutex_lock(),unlock也一樣

Linux——線程3|線程互斥和同步

lock過程:

在進程或線程角度,是如何看待CPU上寄存器的,CPU內部的寄存器,本質叫做當前執(zhí)行流的上下文。寄存器的空間是被所有的執(zhí)行流共享的,但是寄存器的內容是被每一個執(zhí)行流私有的,因為這些是當前執(zhí)行流的上下文。

%al是CPU中的一個寄存器,一開始把0放到該寄存器中,0雖然被放到了寄存器中,但0是某個線程的上下文,接下來進行交換xchgb,該語句只有一句,所以該語句是原子性的,這里的含義是把寄存器的值和鎖的值做交換。交換玩之后去判斷寄存器內容,如果>0,就返回,即鎖申請成功,反之阻塞掛起。

該圖右邊是內存,mtx是鎖。

Linux——線程3|線程互斥和同步

當執(zhí)行完第一條語句之后,線程有可能被切換,線程被切走的時候是帶著數(shù)據(jù)走的,走的時候帶走了寄存器里放進去的0,當新線程來了之后,新線程照樣從第一句語句開始執(zhí)行(這是加鎖操作必須的),新線程把0放了進來,也就是說此時倆個線程都有0,進而說明,寄存器是共享的,但寄存器里面的內容是私有的。

當?shù)诙€線程執(zhí)行完第二條語句后,此時線程被切走,寄存器里現(xiàn)在是1,mtx里面是0,第二個線程被切走的時候要帶走自己的上下文,即把1帶走,之后第一個線程被切了回來,第一個線程走的時候帶的是0,第一個線程回來之后在寄存器里面放了0,之后第一個線程繼續(xù)執(zhí)行語句,由于走的時候第一條語句已經(jīng)執(zhí)行完了,現(xiàn)在要執(zhí)行第二條交換語句(此時內存里mtx是0),交換之后,寄存器里和mtx都是0(0和0交換),第一個線程做判斷,發(fā)現(xiàn)寄存器里的值是0,這時候就把第一個線程掛起,掛起的時候第一個線程又把上下文數(shù)據(jù)0帶走了,這時候恢復第二個線程,把1恢復到寄存器,由于走的時候完成了交換,所以現(xiàn)在進行判斷操作,寄存器里內容>0,直接返回,此時申請鎖成功,lock調用被返回pthread_mutex_lock也被返回,之后繼續(xù)執(zhí)行后續(xù)的代碼。

交換這一行是真正的申請鎖。這里1被所有的線程輪流式的拿到,而且這個數(shù)字1永遠只有1個,而且

不會有任何新增的數(shù)據(jù)存在,這個1就是鎖。

誰來保證鎖的安全?

自己保證,通過一行匯編的方式來保證原子性。

鎖的實現(xiàn)就是上面所述內容:簡單來說通過內存數(shù)據(jù)和CPU寄存器數(shù)據(jù)進行交換。

可重入VS線程安全

可重入是針對函數(shù)來說的,一個函數(shù)被多個執(zhí)行流重復進入的現(xiàn)象叫可重入,在重入期間如果該函數(shù)沒問題,該函數(shù)就叫可重入函數(shù)。

線程安全:多個線程并發(fā)同一段代碼時,不會出現(xiàn)不同的結果。常見對全局變量或者靜態(tài)變量進行操作,并且沒有鎖保護的情況下,會出現(xiàn)該問題。

常見的線程不安全的情況

  1. 不保護共享變量的函數(shù)

  1. 函數(shù)狀態(tài)隨著被調用,狀態(tài)發(fā)生變化的函數(shù)

  1. 返回指向靜態(tài)變量指針的函數(shù)

  1. 調用線程不安全函數(shù)的函數(shù)

常見的線程安全的情況

  1. 每個線程對全局變量或者靜態(tài)變量只有讀取的權限,而沒有寫入的權限,一般來說這些線程是安全的

  1. 類或者接口對于線程來說都是原子操作

  1. 多個線程之間的切換不會導致該接口的執(zhí)行結果存在二義性

常見不可重入的情況

  1. 調用了malloc/free函數(shù),因為malloc函數(shù)是用全局鏈表來管理堆的

  1. 調用了標準I/O庫函數(shù),標準I/O庫的很多實現(xiàn)都以不可重入的方式使用全局數(shù)據(jù)結構

  1. 可重入函數(shù)體內使用了靜態(tài)的數(shù)據(jù)結構

常見可重入的情況

  1. 不使用全局變量或靜態(tài)變量

  1. 不使用用malloc或者new開辟出的空間

  1. 不調用不可重入函數(shù)

  1. 不返回靜態(tài)或全局數(shù)據(jù),所有數(shù)據(jù)都有函數(shù)的調用者提供

  1. 使用本地數(shù)據(jù),或者通過制作全局數(shù)據(jù)的本地拷貝來保護全局數(shù)據(jù)

可重入與線程安全聯(lián)系

  1. 函數(shù)是可重入的,那就是線程安全的

  1. 函數(shù)是不可重入的,那就不能由多個線程使用,有可能引發(fā)線程安全問題

  1. 如果一個函數(shù)中有全局變量,那么這個函數(shù)既不是線程安全也不是可重入的(例如搶票成程序,每個線程都在對全局變量做修改)。

可重入與線程安全區(qū)別

  1. 可重入函數(shù)是線程安全函數(shù)的一種

  1. 線程安全不一定是可重入的,而可重入函數(shù)則一定是線程安全的。

  1. 如果將對臨界資源的訪問加上鎖,則這個函數(shù)是線程安全的,但如果這個重入函數(shù)若鎖還未釋放則會產(chǎn)生死鎖,因此是不可重入的。

注意:如果一個函數(shù)是可重入的,它一定是線程安全的,如果是線程安全的,但不一定可重入。

死鎖

我們在實際中不可能只用一把鎖,我們可能會用多把鎖,這里以倆把鎖為例。

線程A要完成某些工作,申請鎖1和鎖2。線程B也需要倆把鎖,先申請鎖2,再申請鎖1。我們單個申請一把鎖是原子的,當一把鎖申請完再去申請另一把鎖,可能會出問題,如這里的線程A,B,倆個同時運行線程A拿鎖1,線程B拿鎖2,接下來線程A申請鎖2,線程B申請鎖1,此時就會出現(xiàn)問題,雙方想要的鎖都被對方拿到。此時出現(xiàn)了互相申請對方鎖的情況,這種情況就叫死鎖。

Linux——線程3|線程互斥和同步

死鎖是指在一組進程中的各個進程均占有不會釋放的資源,但因互相申請被其他進程所站用不會釋放的資源而處于的一種永久等待狀態(tài)。當只有一把鎖的時候,也有可能會產(chǎn)生死鎖。

當我們把搶票程序里面解鎖的地方,改為申請鎖

Linux——線程3|線程互斥和同步
Linux——線程3|線程互斥和同步

此時程序卡在了這里

Linux——線程3|線程互斥和同步

死鎖四個必要條件

  1. 互斥條件:一個資源每次只能被一個執(zhí)行流使用

  1. 請求與保持條件:一個執(zhí)行流因請求資源而阻塞時,對已獲得的資源保持不放

  1. 不剝奪條件:一個執(zhí)行流已獲得的資源,在末使用完之前,不能強行剝奪

  1. 循環(huán)等待條件:若干執(zhí)行流之間形成一種頭尾相接的循環(huán)等待資源的關系

避免死鎖

  1. 破壞死鎖的四個必要條件

  1. 加鎖順序一致

  1. 避免鎖未釋放的場景

  1. 資源一次性分配

避免死鎖算法

  1. 死鎖檢測算法(了解)

  1. 銀行家算法(了解)

pthrad_mutex_trylock

pthread_mutex_trylock() 是 pthread_mutex_lock() 的非阻塞版本。如果 mutex 所引用的互斥對象當前被任何線程(包括當前線程)鎖定,則將立即返回該調用。否則,該互斥鎖將處于鎖定狀態(tài),調用線程是其屬主。

Linux——線程3|線程互斥和同步

pthread_mutex_trylock() 在成功完成之后會返回零。其他任何返回值都表示出現(xiàn)了錯誤。如果出現(xiàn)以下任一情況,該函數(shù)將失敗并返回對應的值。文章來源地址http://www.zghlxwxcb.cn/news/detail-449771.html

到了這里,關于Linux——線程3|線程互斥和同步的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Linux——線程的同步與互斥

    Linux——線程的同步與互斥

    目錄 模擬搶火車票的過程 代碼示例 thread.cc Thread.hpp 運行結果 分析原因 tickets減到-2的本質? 解決搶票出錯的方案 臨界資源的概念 原子性的概念 加鎖 定義 初始化 銷毀 代碼形式如下 代碼示例1: 代碼示例2: 總結 如何看待鎖 申請失敗將會阻塞 ?pthread_mutex_tyrlock 互斥鎖實現(xiàn)

    2024年02月06日
    瀏覽(27)
  • 【Linux】多線程互斥與同步

    【Linux】多線程互斥與同步

    互斥 指的是一種機制,用于確保在同一時刻只有一個進程或線程能夠訪問共享資源或執(zhí)行臨界區(qū)代碼。 互斥的目的是 防止多個并發(fā)執(zhí)行的進程或線程訪問共享資源時產(chǎn)生競爭條件,從而保證數(shù)據(jù)的一致性和正確性 ,下面我們來使用多線程來模擬實現(xiàn)一個搶票的場景,看看所

    2024年02月09日
    瀏覽(16)
  • 【Linux】多線程2——線程互斥與同步/多線程應用

    【Linux】多線程2——線程互斥與同步/多線程應用

    ??上文主要介紹了多線程之間的獨立資源,本文將詳細介紹多線程之間的 共享資源 存在的問題和解決方法。 intro 多線程共享進程地址空間,包括創(chuàng)建的全局變量、堆、動態(tài)庫等。下面是基于全局變量實現(xiàn)的一個多線程搶票的demo。 發(fā)現(xiàn)錯誤:線程搶到負數(shù)編號的票,為什么

    2024年02月10日
    瀏覽(20)
  • 【關于Linux中----線程互斥與同步】

    【關于Linux中----線程互斥與同步】

    先來用代碼模擬一個搶票的場景,四個線程不停地搶票,一共有1000張票,搶完為止,代碼如下: 執(zhí)行結果如下: 可以看到,最后出現(xiàn)了票數(shù)為負數(shù)的情況,很顯然這是錯誤的,是不應該出現(xiàn)的。 為什么會出現(xiàn)這種情況? 首先要明確,上述的幾個線程是不能同時執(zhí)行搶票的

    2023年04月08日
    瀏覽(17)
  • 【Linux】多線程 --- 線程同步與互斥+生產(chǎn)消費模型

    【Linux】多線程 --- 線程同步與互斥+生產(chǎn)消費模型

    人生總是那么痛苦嗎?還是只有小時候是這樣? —總是如此 1. 假設現(xiàn)在有一份共享資源tickets,如果我們想讓多個線程都對這個資源進行操作,也就是tickets- -的操作,但下面兩份代碼分別出現(xiàn)了不同的結果,上面代碼并沒有出現(xiàn)問題,而下面代碼卻出現(xiàn)了票為負數(shù)的情況,這

    2024年02月06日
    瀏覽(21)
  • 『Linux』第九講:Linux多線程詳解(三)_ 線程互斥 | 線程同步

    『Linux』第九講:Linux多線程詳解(三)_ 線程互斥 | 線程同步

    「前言」文章是關于Linux多線程方面的知識,上一篇是?Linux多線程詳解(二),今天這篇是 Linux多線程詳解(三),內容大致是線程互斥與線程同步,講解下面開始! 「歸屬專欄」Linux系統(tǒng)編程 「主頁鏈接」個人主頁 「筆者」楓葉先生(fy) 「楓葉先生有點文青病」「每篇一句

    2024年02月02日
    瀏覽(22)
  • Linux pthread線程操作 和 線程同步與互斥操作

    Linux pthread線程操作 和 線程同步與互斥操作

    在Linux系統(tǒng)中玩線程,使用pthread,這篇博客記錄如何 創(chuàng)建線程 和 使用線程 和線程的 同步 與 互斥 。 還有一份nginx線程池的代碼供大家閱讀學習! 目錄 一、簡介 什么是線程 線程的優(yōu)點、缺點 線程的應用場合 二、線程的使用 1.? 創(chuàng)建線程 - pthread_create 2.? 線程的終止 - pt

    2024年02月02日
    瀏覽(23)
  • 【Linux】多線程02 --- 線程的同步互斥問題及生產(chǎn)消費模型

    【Linux】多線程02 --- 線程的同步互斥問題及生產(chǎn)消費模型

    ?? 作者: 阿潤菜菜 ?? 專欄: Linux系統(tǒng)編程 線程同步互斥問題是指多線程程序中,如何保證共享資源的正確訪問和線程間的協(xié)作。 因為線程互斥是實現(xiàn)線程同步的基礎和前提,我們先講解線程互斥問題。 在多線程中,假設我們有一個黃牛搶票的代碼,其中有一份共享資源

    2024年02月08日
    瀏覽(16)
  • 一文搞定Linux線程間通訊 / 線程同步方式-互斥鎖、讀寫鎖、自旋鎖、信號量、條件變量、信號等等

    目錄 線程間通訊 / 線程同步方式 鎖機制 互斥鎖(Mutex) 讀寫鎖(rwlock) 自旋鎖(spin) 信號量機制(Semaphore) 條件變量機制 信號(Signal) 線程間通訊 / 線程同步方式 p.s 以下有很多段落是直接引用,沒有使用 markdown 的 “引用” 格式,出處均已放出。 參考 / 引用: 100as

    2024年02月10日
    瀏覽(24)
  • 【Linux系統(tǒng)編程:線程】 線程控制 -- 創(chuàng)建、終止、等待、分離 | 線程互斥與同步 | 互斥量與條件變量 | 生產(chǎn)者消費者模型 | 線程池 | STL/智能指針與線程安全 | 讀者寫者模型

    【Linux系統(tǒng)編程:線程】 線程控制 -- 創(chuàng)建、終止、等待、分離 | 線程互斥與同步 | 互斥量與條件變量 | 生產(chǎn)者消費者模型 | 線程池 | STL/智能指針與線程安全 | 讀者寫者模型

    寫在前面 本文重點: 了解線程概念,理解線程與進程區(qū)別與聯(lián)系。 學會線程控制,線程創(chuàng)建,線程終止,線程等待。 了解線程分離與線程安全。 學會線程同步。 學會使用互斥量,條件變量,posix 信號量,以及讀寫鎖。 理解基于讀寫鎖的讀者寫者問題。 一、線程概念 ??

    2024年02月04日
    瀏覽(104)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包