日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
C++里++i是原子操作嗎?

1.什么是原子操作

在多線程環(huán)境下,原子操作是指不會(huì)被線程調(diào)度機(jī)制打斷的操作;這種操作一旦開始,就一直運(yùn)行到結(jié)束,中間不會(huì)有任何 context switch (切換到另一個(gè)線程)。

原子操作可以確保某些特定操作在多線程條件下,不會(huì)由于線程切換而導(dǎo)致數(shù)據(jù)污染。比如,對(duì)一個(gè)變量的讀/寫操作,就是一個(gè)常見的需要原子化的場景。如果把這樣的讀/寫操作設(shè)計(jì)成原子操作,就可以避免多線程競爭導(dǎo)致的數(shù)據(jù)不一致問題。

2.++i 是否原子操作

在 C++ 中,對(duì)一個(gè)變量的自增(++)操作看似很簡單,理論上它包含:

  • 讀變量原值
  • 對(duì)原值加 1
  • 將結(jié)果寫回變量

例如:

int i = 0; 
++i;

但是在多線程環(huán)境下,這三個(gè)步驟如果被打斷,可能導(dǎo)致如下結(jié)果:

  • 線程1 讀到i=0
  • 線程2也讀到i=0
  • 線程1對(duì)i加1并寫入,現(xiàn)在i=1
  • 線程2對(duì)i加1并寫入,這時(shí)覆蓋了線程1的寫入,又使得i=1

很明顯,實(shí)際的運(yùn)行次數(shù)是2次,但最終結(jié)果是i=1,這就是數(shù)據(jù)污染的例子。

為了避免上述情況,C++編譯器在編譯過程中,會(huì)自動(dòng)將一些看似簡單的操作(例如自增操作)轉(zhuǎn)換為原子指令,從而保證其原子性。

這種特性與具體的編譯器實(shí)現(xiàn)相關(guān),比如主流的GNU編譯器和MSVC編譯器都對(duì)自增操作進(jìn)行了優(yōu)化,確保其原子執(zhí)行。

所以可以認(rèn)為,在絕大多數(shù)C++實(shí)現(xiàn)中,++i這個(gè)自增操作是原子的。但是仍有一些例外情況需要注意,比如在嵌入式平臺(tái)上可能需要開發(fā)者顯式指定操作的原子性。

3. 如何保證操作的原子性

在不能依賴編譯器優(yōu)化的情況下,C++11提供了一些方法可以保證操作的原子性:

(1) atomic類型:提供了一些原子類型,對(duì)其操作天然原子

int i = 0; 
++i;

(2) mutex:使用mutex可以在臨界區(qū)內(nèi)執(zhí)行一個(gè)原子塊

std::mutex m;
m.lock();
// critical section
cnt++; 
m.unlock();

(3) lock-free編程:通過CAS(compare-and-swap)等原子指令實(shí)現(xiàn)非阻塞同步

atomic_int val;
int expect = val.load();
while(!val.compare_exchange_weak(expect, expect + 1)) {
  expect = val.load(); 
} atomic_int val;
int expect = val.load();
while(!val.compare_exchange_weak(expect, expect + 1)) {
  expect = val.load(); 
}

4. 總結(jié)

綜上所述,在大多數(shù)普通的桌面程序和服務(wù)端程序中,++i這樣的自增操作可以看作是原子的,編譯器會(huì)做出優(yōu)化。但是對(duì)于嵌入式開發(fā)等要求原子操作顯式控制的場景,C++11提供了一些新的原子類型和同步原語來保證操作的原子執(zhí)行。


網(wǎng)頁標(biāo)題:C++里++i是原子操作嗎?
網(wǎng)頁路徑:http://www.dlmjj.cn/article/dhhjssd.html