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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ARM平台下独占访问指令LDREX和STREX的原理与使用详解

發(fā)布時(shí)間:2025/3/21 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ARM平台下独占访问指令LDREX和STREX的原理与使用详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

為了實(shí)現(xiàn)線程間同步,一般都要在執(zhí)行關(guān)鍵代碼段之前加互斥(Mutex)鎖,且在執(zhí)行完關(guān)鍵代碼段之后解鎖。為了實(shí)現(xiàn)所謂的互斥鎖的概念,一般都需要所在平臺(tái)提供支持。

在計(jì)算機(jī)領(lǐng)域里,如果要在多線程的情況下要保持?jǐn)?shù)據(jù)的同步,需要引入稱作Load-Link(LL)和Store-Conditional(SC)的操作,通常簡稱為LL/SC。LL操作返回一個(gè)內(nèi)存地址上當(dāng)前存儲(chǔ)的值,后面的SC操作,會(huì)向這個(gè)內(nèi)存地址寫入一個(gè)新值,但是只有在這個(gè)內(nèi)存地址上存儲(chǔ)的值,從上個(gè)LL操作開始直到現(xiàn)在都沒有發(fā)生改變的情況下,寫入操作才能成功,否則都會(huì)失敗。這個(gè)操作非常重要,是很多平臺(tái)實(shí)現(xiàn)基本原子操作的基礎(chǔ)。 對(duì)于ARM平臺(tái)來說,也在硬件層面上提供了對(duì)LL/SC的支持,LL操作用的是LDREX指令,SC操作用的是STREX指令。

本文主要用來說明ARM平臺(tái)上特有的獨(dú)占訪問指令LDREX和STREX的工作原理,以及如何使用。而它們也是ARM平臺(tái)上,實(shí)現(xiàn)互斥鎖等線程同步工具的基礎(chǔ)。

我們先來看看LDREX和STREX兩條指令的語義。其實(shí)LDREX和STREX指令,是將單純的更新內(nèi)存的原子操作分成了兩個(gè)獨(dú)立的步驟。

1)LDREX用來讀取內(nèi)存中的值,并標(biāo)記對(duì)該段內(nèi)存的獨(dú)占訪問:

LDREX Rx, [Ry]

上面的指令意味著,讀取寄存器Ry指向的4字節(jié)內(nèi)存值,將其保存到Rx寄存器中,同時(shí)標(biāo)記對(duì)Ry指向內(nèi)存區(qū)域的獨(dú)占訪問。

如果執(zhí)行LDREX指令的時(shí)候發(fā)現(xiàn)已經(jīng)被標(biāo)記為獨(dú)占訪問了,并不會(huì)對(duì)指令的執(zhí)行產(chǎn)生影響。

2)而STREX在更新內(nèi)存數(shù)值時(shí),會(huì)檢查該段內(nèi)存是否已經(jīng)被標(biāo)記為獨(dú)占訪問,并以此來決定是否更新內(nèi)存中的值:

STREX Rx, Ry, [Rz]

如果執(zhí)行這條指令的時(shí)候發(fā)現(xiàn)已經(jīng)被標(biāo)記為獨(dú)占訪問了,則將寄存器Ry中的值更新到寄存器Rz指向的內(nèi)存,并將寄存器Rx設(shè)置成0。指令執(zhí)行成功后,會(huì)將獨(dú)占訪問標(biāo)記位清除。

而如果執(zhí)行這條指令的時(shí)候發(fā)現(xiàn)沒有設(shè)置獨(dú)占標(biāo)記,則不會(huì)更新內(nèi)存,且將寄存器Rx的值設(shè)置成1。

一旦某條STREX指令執(zhí)行成功后,以后再對(duì)同一段內(nèi)存嘗試使用STREX指令更新的時(shí)候,會(huì)發(fā)現(xiàn)獨(dú)占標(biāo)記已經(jīng)被清空了,就不能再更新了,從而實(shí)現(xiàn)獨(dú)占訪問的機(jī)制。

大致的流程就是這樣,但是ARM內(nèi)部為了實(shí)現(xiàn)這個(gè)功能,還有不少復(fù)雜的情況要處理。

在ARM系統(tǒng)中,內(nèi)存有兩種不同且對(duì)立的屬性,即共享(Shareable)和非共享(Non-shareable)。共享意味著該段內(nèi)存可以被系統(tǒng)中不同處理器訪問到,這些處理器可以是同構(gòu)的也可以是異構(gòu)的。而非共享,則相反,意味著該段內(nèi)存只能被系統(tǒng)中的一個(gè)處理器所訪問到,對(duì)別的處理器來說不可見。

為了實(shí)現(xiàn)獨(dú)占訪問,ARM系統(tǒng)中還特別提供了所謂獨(dú)占監(jiān)視器(Exclusive Monitor)的東西,其結(jié)構(gòu)大致如下:

可以看出來,一共有兩種類型的獨(dú)占監(jiān)視器。每一個(gè)處理器內(nèi)部都有一個(gè)本地監(jiān)視器(Local Monitor),且在整個(gè)系統(tǒng)范圍內(nèi)還有一個(gè)全局監(jiān)視器(Global Monitor)。

如果要對(duì)非共享內(nèi)存區(qū)中的值進(jìn)行獨(dú)占訪問,只需要涉及本處理器內(nèi)部的本地監(jiān)視器就可以了;而如果要對(duì)共享內(nèi)存區(qū)中的內(nèi)存進(jìn)行獨(dú)占訪問,除了要涉及到本處理器內(nèi)部的本地監(jiān)視器外,由于該內(nèi)存區(qū)域可以被系統(tǒng)中所有處理器訪問到,因此還必須要由全局監(jiān)視器來協(xié)調(diào)。

對(duì)于本地監(jiān)視器來說,它只標(biāo)記了本處理器對(duì)某段內(nèi)存的獨(dú)占訪問,在調(diào)用LDREX指令時(shí)設(shè)置獨(dú)占訪問標(biāo)志,在調(diào)用STREX指令時(shí)清除獨(dú)占訪問標(biāo)志。

而對(duì)于全局監(jiān)視器來說,它可以標(biāo)記每個(gè)處理器對(duì)某段內(nèi)存的獨(dú)占訪問。也就是說,當(dāng)一個(gè)處理器調(diào)用LDREX訪問某段共享內(nèi)存時(shí),全局監(jiān)視器只會(huì)設(shè)置針對(duì)該處理器的獨(dú)占訪問標(biāo)記,不會(huì)影響到其它的處理器。當(dāng)在以下兩種情況下,會(huì)清除某個(gè)處理器的獨(dú)占訪問標(biāo)記:

1)當(dāng)該處理器調(diào)用LDREX指令,申請(qǐng)獨(dú)占訪問另一段內(nèi)存時(shí);

2)當(dāng)別的處理器成功更新了該段獨(dú)占訪問內(nèi)存值時(shí)。

對(duì)于第二種情況,也就是說,當(dāng)獨(dú)占內(nèi)存訪問內(nèi)存的值在任何情況下,被任何一個(gè)處理器更改過之后,所有申請(qǐng)獨(dú)占該段內(nèi)存的處理器的獨(dú)占標(biāo)記都會(huì)被清空。

另外,更新內(nèi)存的操作不一定非要是STREX指令,任何其它存儲(chǔ)指令都可以。但如果不是STREX的話,則沒法保證獨(dú)占訪問性。

現(xiàn)在的處理器基本上都是多核的,一個(gè)芯片上集成了多個(gè)處理器。而且對(duì)于一般的操作系統(tǒng),系統(tǒng)內(nèi)存基本上都被設(shè)置上了共享屬性,也就是說對(duì)系統(tǒng)中所有處理器可見。因此,我們這里主要分析多核系統(tǒng)中對(duì)共享內(nèi)存的獨(dú)占訪問的情況。

為了更加清楚的說明,我們可以舉一個(gè)例子。假設(shè)系統(tǒng)中有兩個(gè)處理器內(nèi)核,而一個(gè)程序由三個(gè)線程組成,其中兩個(gè)線程被分配到了第一個(gè)處理器上,另外一個(gè)線程被分配到了第二個(gè)處理器上。且他們的執(zhí)行序列如下:

大致經(jīng)歷的步驟如下:

1)CPU2上的線程3最早執(zhí)行LDREX,鎖定某段共享內(nèi)存區(qū)域。它會(huì)相應(yīng)更新本地監(jiān)視器和全局監(jiān)視器。

2)然后,CPU1上的線程1執(zhí)行LDREX,它也會(huì)更新本地監(jiān)視器和全局監(jiān)視器。這時(shí)在全局監(jiān)視器上,CPU1和CPU2都對(duì)該段內(nèi)存做了獨(dú)占標(biāo)記。

3)接著,CPU1上的線程2執(zhí)行LDREX指令,它會(huì)發(fā)現(xiàn)本處理器的本地監(jiān)視器對(duì)該段內(nèi)存有了獨(dú)占標(biāo)記,同時(shí)全局監(jiān)視器上CPU1也對(duì)該段內(nèi)存做了獨(dú)占標(biāo)記,但這并不會(huì)影響這條指令的操作。

4)再下來,CPU1上的線程1最先執(zhí)行了STREX指令,嘗試更新該段內(nèi)存的值。它會(huì)發(fā)現(xiàn)本地監(jiān)視器對(duì)該段內(nèi)存是有獨(dú)占標(biāo)記的,而全局監(jiān)視器上CPU1也有該段內(nèi)存的獨(dú)占標(biāo)記,則更新內(nèi)存值成功。同時(shí),清除本地監(jiān)視器對(duì)該段內(nèi)存的獨(dú)占標(biāo)記,還有全局監(jiān)視器所有處理器對(duì)該段內(nèi)存的獨(dú)占標(biāo)記。

5)下面,CPU2上的線程3執(zhí)行STREX指令,也想更新該段內(nèi)存值。它會(huì)發(fā)現(xiàn)本地監(jiān)視器擁有對(duì)該段內(nèi)存的獨(dú)占標(biāo)記,但是在全局監(jiān)視器上CPU1沒有了該段內(nèi)存的獨(dú)占標(biāo)記(前面一步清空了),則更新不成功。

6)最后,CPU1上的線程2執(zhí)行STREX指令,試著更新該段內(nèi)存值。它會(huì)發(fā)現(xiàn)本地監(jiān)視器已經(jīng)沒有了對(duì)該段內(nèi)存的獨(dú)占標(biāo)記(第4步清除了),則直接更新失敗,不需要再查全局監(jiān)視器了。

所以,可以看出來,這套機(jī)制的精髓就是,無論有多少個(gè)處理器,有多少個(gè)地方會(huì)申請(qǐng)對(duì)同一個(gè)內(nèi)存段進(jìn)行操作,保證只有最早的更新可以成功,這之后的更新都會(huì)失敗。失敗了就證明對(duì)該段內(nèi)存有訪問沖突了。實(shí)際的使用中,可以重新用LDREX讀取該段內(nèi)存中保存的最新值,再處理一次,再嘗試保存,直到成功為止。

還有一點(diǎn)需要說明,LDREX和STREX是對(duì)內(nèi)存中的一個(gè)字(Word,32 bit)進(jìn)行獨(dú)占訪問的指令。如果想獨(dú)占訪問的內(nèi)存區(qū)域不是一個(gè)字,還有其它的指令:

1)LDREXB和STREXB:對(duì)內(nèi)存中的一個(gè)字節(jié)(Byte,8 bit)進(jìn)行獨(dú)占訪問;

2)LDREXH和STREXH:中的一個(gè)半字(Half Word,16 bit)進(jìn)行獨(dú)占訪問;

3)LDREXD和STREXD:中的一個(gè)雙字(Double Word,64 bit)進(jìn)行獨(dú)占訪問。

它們必須配對(duì)使用,不能混用。

在ARMv8指令集下,LDREX指令被改名成了LDXR指令,而STREX指令被改名成了STXR指令,功能基本上是一樣的,除了添加了一個(gè)新的特性。當(dāng)全局監(jiān)視器標(biāo)記的對(duì)某段內(nèi)存的獨(dú)占訪問被清空后,將向所有標(biāo)記了對(duì)該段內(nèi)存獨(dú)占訪問的CPU核都發(fā)送事件,將它們從WFE指令中喚醒,繼續(xù)執(zhí)行。

總結(jié)

以上是生活随笔為你收集整理的ARM平台下独占访问指令LDREX和STREX的原理与使用详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。