日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【干货】同步与互斥的失败例子

發布時間:2023/12/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【干货】同步与互斥的失败例子 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

韋東山老師最新錄制的驅動大全之<<同步與互斥>>收費視頻已經在淘寶上架銷售 ,一共7節,良心價29元,同時已經同步到CSDN , 51CTO , 電子發燒友,騰訊課堂等平臺。

本文是其中一節《同步與互斥的失敗例子》視頻配套文檔,

《同步與互斥的失敗例子》免費試看版(2分鐘,完整版7分46秒):

《同步與互斥的失敗例子》完整版 購買鏈接:

https://item.taobao.com/item.htm?id=620987021249? (復制到瀏覽器打開)

光看文檔可能難度稍大,建議結合視頻進行學習;gg完畢,開始干貨。


1.2 同步與互斥的失敗例子

注意:本節在GIT上沒有源碼。

GIT地址:

git clone https://e.coding.net/weidongshan/01_all_series_quickstart.git

一句話理解同步與互斥:我等你用完廁所,我再用廁所。什么叫同步?就是條件不允許,我要等等。什么是互斥?你我早起都要用廁所,誰先搶到誰先用,中途不被打擾。

同步與互斥經常放在一起講,是因為它們之間的關系很大,“互斥”操作可以使用“同步”來實現。我“等”你用完廁所,我再用廁所。這不就是用“同步”來實現“互斥”嗎?有時候看代碼更容易理解,偽代碼如下:

01?void??搶廁所(void) 02?{ 03????if?(有人在用)?我瞇一會; 04????用廁所; 05????喂,醒醒,有人要用廁所嗎; 06?}

假設有A、B兩人早起搶廁所,A先行一步占用了;B慢了一步,于是就瞇一會;當A用完后叫醒B,B也就愉快地上廁所了。

在這個過程中,A、B是互斥地訪問“廁所”,“廁所”被稱之為臨界資源。我們使用了“休眠-喚醒”的同步機制實現了“臨界資源”的“互斥訪問”。

上面是一個有“味道”的例子,回到程序員的世界,一個驅動程序同時只能有一個APP使用,怎么實現?

1.2.1 失敗例子1

01?static?int?valid?=?1; 02 03?static?ssize_t?gpio_key_drv_open?(struct?inode?*node,?struct?file?*file) 04?{ 05??????if?(!valid) 06??????{ 07??????????????return?-EBUSY; 08??????} 09??????else 10??????{ 11??????????????valid?=?0; 12??????} 13 14??????return?0;?//成功 15?} 16 17?static?int?gpio_key_drv_close?(struct?inode?*node,?struct?file?*file) 18?{ 19??????valid?=?1; 20??????return?0; 21?} 22

看第5行,我們使用一個全局變量valid來實現互斥訪問。這有問題嗎?很大概率沒問題,但是并非萬無一失。

注意:編寫驅動程序時,要有系統的概念,程序A調用驅動程序時,它可能被程序B打斷,程序B也去調用這個驅動程序。下圖是一個例子,程序A在調用驅動程序的中途被程序B搶占了CPU資源:

程序A執行到第11行之前,被程序B搶占了,這時valid尚未被改成0;程序B調用gpio_key_drv_open時,發現valid等于1,所以成功返回0;當程序A繼續從第11行執行時,它最終也成功返回0;這樣程序A、B都成功打開了驅動程序。

注意:在內核態,程序A不是主動去休眠、主動放棄CPU資源;而是被優先級更高的程序B搶占了,這種行為被稱為“preempt”(搶占)。

1.2.2 失敗例子2

上面的例子是不是第5行到第11行的時間跨度大長了?再優化一下程序行不行?代碼如下:

01?static?int?valid?=?1; 02 03?static?ssize_t?gpio_key_drv_open?(struct?inode?*node,?struct?file?*file) 04?{ 05??????if?(--valid) 06??????{ 07??????????????valid++; 08??????????????return?-EBUSY; 09??????} 10??????return?0; 11?} 12 13?static?int?gpio_key_drv_close?(struct?inode?*node,?struct?file?*file) 14?{ 15??????valid?=?1; 16??????return?0; 17?} 18

第5行先減1再判斷,這樣可以更大概率地避免問題,但是還是不能確保萬無一失。對數據的修改分為3步:讀出來、修改、寫進去。請看下圖:

進程A在讀出valid時發現它是1,減1后為0,這時if不成立;但是修改后的值尚未寫回內存;假設這時被程序B搶占,程序B讀出valid仍為1,減1后為0,這時if不成立,最后成功返回;輪到A繼續執行,它把0值寫到valid變量,最后也成功返回。這樣程序A、B都成功打開了驅動程序。

1.2.3 失敗例子3

前面2個例子,都是在修改valid的過程中被別的進程搶占了,那么在修改valid的時候直接關中斷不就可以了嗎?

01?static?int?valid?=?1; 02 03?static?ssize_t?gpio_key_drv_open?(struct?inode?*node,?struct?file?*file) 04?{ 05???????unsigned?long?flags; 06???????raw_local_irq_save(flags);?//?關中斷 07??????if?(--valid) 08??????{ 09??????????????valid++; 10??????????????raw_local_irq_restore(flags);??//?恢復之前的狀態 11??????????????return?-EBUSY; 12??????} 13???????raw_local_irq_restore(flags);??????????//?恢復之前的狀態 14??????return?0; 15?} 16 17?static?int?gpio_key_drv_close?(struct?inode?*node,?struct?file?*file) 18?{ 19??????valid?=?1; 20??????return?0; 21?}

第06行直接關中斷,這樣別的線程、中斷都不能來打擾本線程了,在它讀取、修改valid變量的過程中無人打擾。沒有問題了?

對于單CPU核的系統上述代碼是沒問題的;但是對于SMP系統,你只能關閉當前CPU核的中斷,別的CPU核還可以運行程序,它們也可以來執行這個函數,同樣導致問題,如下圖:

假設CPU 0上進程A、CPU1上進程B同時運行到上圖中讀出valid的地方,它們同時發現valid都是1,減減后都等于0,在第07行判斷條件都不成立,所以在第14行都可以返回0,都可以成功打開驅動。

推薦閱讀:

? ??專輯|Linux文章匯總

? ??專輯|程序人生

? ??專輯|C語言

嵌入式Linux

微信掃描二維碼,關注我的公眾號?

總結

以上是生活随笔為你收集整理的【干货】同步与互斥的失败例子的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。