前言
這個是在面試的時候遇到的問題,當時沒有答出來。回到家以后查了查,整理記錄下來。原問題:什么指令集支持原子操作?其原理是什么?如果考慮到全部的指令集,問題太大了,這里簡化下。以X86和ARM為例。原子操作是不可分割的操作,在執(zhí)行完畢時它不會被任何事件中斷。在單處理器系統(tǒng)(UniProcessor,簡稱 UP)中,能夠在單條指令中完成的操作都可以認為是原子操作,因為中斷只能發(fā)生在指令與指令之間。比如,C語言代碼



X86架構(gòu)
Intel X86指令集提供了指令前綴lock用于鎖定前端串行總線FSB,保證了指令執(zhí)行時不會收到其他處理器的干擾。比如:

DescriptionCauses the processor’s LOCK# signal to be asserted during execution of the accompanying instruction (turns the instruction into an atomic instruction). In a multiprocessor environment, the LOCK# signal ensures that the processor has exclusive use of any shared memory while the signal is asserted.The LOCK prefix can be prepended only to the following instructions and only to those forms of the instructions where the destination operand is a memory operand: ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG. If the LOCK prefix is used with one of these instructions and the source operand is a memory operand, an undefined opcode exception (#UD) may be generated. An undefined opcode exception will also be generated if the LOCK prefix is used with any instruction not in the above list. The XCHG instruction always asserts the LOCK# signal regardless of the presence or absence of the LOCK prefix.The LOCK prefix is typically used with the BTS instruction to perform a read-modify-write operation on a memory location in shared memory environment.The integrity of the LOCK prefix is not affected by the alignment of the memory field. Memory locking is observed for arbitrarily misaligned fields.在執(zhí)行伴隨的指令期間使處理器的LOCK#信號有效(將指令變?yōu)樵又噶睿?。在多處理器環(huán)境中,LOCK#信號確保處理器在信號有效時獨占使用任何共享存儲器。LOCK前綴只能附加在下面的指令之前,并且只適用于那些目標操作數(shù)是內(nèi)存操作數(shù)的指令格式:ADD,ADC,AND,BTC,BTR,BTS,CMPXCHG,CMPXCH8B,CMPXCHG16B,DEC,INC, NEG,NOT,OR,SBB,SUB,XOR,XADD和XCHG。如果LOCK前綴與這些指令之一一起使用,并且源操作數(shù)是內(nèi)存操作數(shù),則可能會生成未定義的操作碼異常(#UD)。如果LOCK前綴與任何不在上述列表中的指令一起使用,也會產(chǎn)生未定義的操作碼異常。無論是否存在LOCK前綴,XCHG指令都始終聲明LOCK#信號。LOCK前綴通常與BTS指令一起使用,以在共享存儲器環(huán)境中的存儲器位置上執(zhí)行讀取 – 修改 – 寫入操作。LOCK前綴的完整性不受存儲器字段對齊的影響。內(nèi)存鎖定是針對任意不對齊的字段。
操作系統(tǒng)中的實現(xiàn)
Linux源碼中對于原子自增一是如下定義的:

static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new)
{
return cmpxchg(&v->counter, old, new);
}
__cmpxchg(ptr, old, new, sizeof(*(ptr)))
__raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
({
__typeof__(*(ptr)) __ret;
__typeof__(*(ptr)) __old = (old);
__typeof__(*(ptr)) __new = (new);
switch (size) {
case __X86_CASE_B:
{
volatile u8 *__ptr = (volatile u8 *)(ptr);
asm volatile(lock "cmpxchgb %2,%1"
: "=a" (__ret), "+m" (*__ptr)
: "q" (__new), "0" (__old)
: "memory");
break;
}
case __X86_CASE_W:
{
volatile u16 *__ptr = (volatile u16 *)(ptr);
asm volatile(lock "cmpxchgw %2,%1"
: "=a" (__ret), "+m" (*__ptr)
: "r" (__new), "0" (__old)
: "memory");
break;
}
case __X86_CASE_L:
{
volatile u32 *__ptr = (volatile u32 *)(ptr);
asm volatile(lock "cmpxchgl %2,%1"
: "=a" (__ret), "+m" (*__ptr)
: "r" (__new), "0" (__old)
: "memory");
break;
}
case __X86_CASE_Q:
{
volatile u64 *__ptr = (volatile u64 *)(ptr);
asm volatile(lock "cmpxchgq %2,%1"
: "=a" (__ret), "+m" (*__ptr)
: "r" (__new), "0" (__old)
: "memory");
break;
}
default:
__cmpxchg_wrong_size();
}
__ret;
})
ARM架構(gòu)
在ARM架構(gòu)下,沒有LOCK#指令,其具體實現(xiàn)如下:## ARMv6之前 早期的ARM架構(gòu)是不支持SMP的,這些單核架構(gòu)的CPU實現(xiàn)原子操作的方式就是通過關(guān)閉CPU中斷來完成的。在Linux對于ARM架構(gòu)的代碼下有如下:


原文標題:對int變量賦值的操作是原子的嗎?為什么?
文章出處:【微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
內(nèi)存
+關(guān)注
關(guān)注
8文章
3124瀏覽量
75268 -
處理器系統(tǒng)
+關(guān)注
關(guān)注
0文章
10瀏覽量
7864 -
C語言代碼
+關(guān)注
關(guān)注
0文章
10瀏覽量
9293
原文標題:對int變量賦值的操作是原子的嗎?為什么?
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
熱點推薦
66ak2h14使用 ldrex過程中出錯
我使用的開發(fā)板是EVMK2H,在使用自旋鎖時候會發(fā)現(xiàn)一直處于死鎖狀態(tài),仿真器調(diào)試發(fā)現(xiàn),無論我內(nèi)存單元中的值是多少,執(zhí)行
LDREX ? R2, [R0] ? ? ? ?;R0為內(nèi)存單元地址
R2讀取到的值始終為0,請問在使用LDREX指令之前還需要做什么配置嗎?
發(fā)表于 06-21 16:55
stm32的Core_cm3.c文件
和STREX是Cortex用來實現(xiàn)互斥訪問,保護臨界資源的指令,LDREX執(zhí)行后,只有離它最近的一條存儲指令(STR,STREX)才能執(zhí)行,其他的存儲指令都會被駁回,而CLREX就是用于清除互斥訪問狀態(tài)
發(fā)表于 07-02 06:19
STM32F7 MPU設置跳入硬件錯誤中
最近在使用STM32F746,將內(nèi)部RAM的MPU屬性設置為MPU_ACCESS_SHAREABLE,發(fā)現(xiàn)如果程序中使用 ldrex 指令,會跳入硬件錯誤中斷,設置成
發(fā)表于 01-30 04:07
ARM平臺上特有的獨占訪問指令LDREX和STREX該怎樣去使用呢
來說,也在硬件層面上提供了對LL/SC的支持,LL操作用的是LDREX指令,SC操作用的是STREX指令。本文主要用來說明ARM平臺上特有的獨占訪問指令LDREX和STREX的工作原理
發(fā)表于 04-22 09:44
AHB-lite總線如何處理獨占訪問
設計。處理器從代碼總線正確引導,并執(zhí)行指令(已禁用ITCM)。問題是我認為普通LDR / STR和LDREX / STREX在AXI總線上沒有區(qū)別。無論我怎么嘗試,STREX指令都將失敗(返回1
發(fā)表于 08-18 11:11
不能將STREX/LDREX與多核共享內(nèi)存訪問一起使用嗎?
我需要確認使用具有共享內(nèi)存區(qū)域的 STREX/LDREX 不會創(chuàng)建全局獨占訪問標簽。所以我們不能將 STREX/LDREX 與多核共享內(nèi)存訪問一起使用。我認為這違反了 cortex-M
發(fā)表于 04-03 07:45
淺談鴻蒙內(nèi)核源碼的原子操作
ARMv6架構(gòu)引入了LDREX和STREX指令,以支持對共享存儲器更縝密的非阻塞同步。由此實現(xiàn)的原子操作能確保對同一數(shù)據(jù)的“讀取-修改-寫入”操作在它的執(zhí)行期間不會被打斷,即操作的原子性。

ARM指令集—SWP指令
。
SWP指令主要是完畢ARM體系架構(gòu)處理器的同步操作。在Linux操作系統(tǒng)中實現(xiàn)信號量的操作??墒谴酥噶钤贏RMv6架構(gòu)后就沒有採用了,而是通過擴展的LDREX和STREX實現(xiàn)。本片文章主要介紹SWP的功能...
發(fā)表于 02-11 15:33
?6次下載

Vybrid非對稱多核架構(gòu)的裸機固件
另一方面是與運行在 Cortex-A5 上的主操作系統(tǒng)進行通信的通信基礎設施。libopencm3 實現(xiàn)目前不支持通信。可能最簡單的通信實現(xiàn)是定義一個可以從雙方訪問的共享內(nèi)存區(qū)域(考慮使用使用獨占加載/存儲指令 LDREX/STREX 的同步機制)。

評論