第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

num+在“int num”中可以是原子的嗎?

num+在“int num”中可以是原子的嗎?

C++ C
達令說 2019-06-16 13:42:05
num+在“int num”中可以是原子的嗎?一般情況下,int num, num++(或++num),作為讀-修改-寫入操作,是非原子..但是我經(jīng)常看到編譯器,例如GCC,為它生成以下代碼(試試這里):因為第5行對應于num++是一條指令,我們能得出結論嗎num++ 是原子的在這種情況下?如果是這樣的話,這是否意味著num++可以在并發(fā)(多線程)方案中使用,而不存在任何數(shù)據(jù)競爭的危險。(例如,我們不需要去做,std::atomic<int>加上相關的成本,因為它是原子的)?更新注意這個問題是不是否增量是原子(它不是,也是這個問題的開場白)。關鍵是它是否能,會,可以在特定情況下,即是否可以在某些情況下利用單指令性質來避免lock前綴。而且,正如公認的答案在關于單處理器計算機的一節(jié)中提到的,以及這個答案在評論和其他人的解釋中,它可以(雖然沒有使用C或C+)。
查看完整描述

3 回答

?
一只斗牛犬

TA貢獻1784條經(jīng)驗 獲得超2個贊

.現(xiàn)在讓我們啟用優(yōu)化:


f():

        rep ret

好吧,讓我們給它一個機會:


void f(int& num)

{

  num = 0;

  num++;

  --num;

  num += 6;

  num -=5;

  --num;

}

結果:


f(int&):

        mov     DWORD PTR [rdi], 0

        ret

另一個觀察線程(甚至忽略緩存同步延遲)沒有機會觀察單個更改。


與之相比:


#include <atomic>


void f(std::atomic<int>& num)

{

  num = 0;

  num++;

  --num;

  num += 6;

  num -=5;

  --num;

}

其結果是:


f(std::atomic<int>&):

        mov     DWORD PTR [rdi], 0

        mfence

        lock add        DWORD PTR [rdi], 1

        lock sub        DWORD PTR [rdi], 1

        lock add        DWORD PTR [rdi], 6

        lock sub        DWORD PTR [rdi], 5

        lock sub        DWORD PTR [rdi], 1

        ret

現(xiàn)在,每項修改都是:


在另一個線程中可以觀察到,并且

尊重發(fā)生在其他線程中的類似修改。

原子性不只是在指令級,它涉及到從處理器到緩存,到內(nèi)存和返回的整個管道。


進一步信息

的更新的優(yōu)化效果std::atomicS.


c+標準具有“似乎”規(guī)則,允許編譯器重新排序代碼,甚至可以重寫代碼,條件是結果具有完全相同效果(包括副作用),就好像它只是簡單地執(zhí)行了您的代碼。


如果規(guī)則是保守的,特別涉及原子。


考慮:


void incdec(int& num) {

    ++num;

    --num;

}

由于沒有互斥鎖、Atomics或任何其他影響線程間排序的構造,我認為編譯器可以自由地將此函數(shù)重寫為NOP,例如:


void incdec(int&) {

    // nada

}

這是因為在c+內(nèi)存模型中,不可能有另一個線程觀察增量的結果。當然,如果num曾.volatile(可能會影響硬件行為)。但是在這種情況下,這個函數(shù)將是唯一修改這個內(nèi)存的函數(shù)(否則程序是格式錯誤的)。


然而,這是一場不同的球賽:


void incdec(std::atomic<int>& num) {

    ++num;

    --num;

}

num是原子。對它的改變必觀察其他正在觀察的線索。更改這些線程本身的值(例如在增量和減少之間將值設置為100)將對num的最終值產(chǎn)生非常深遠的影響。


下面是一個演示:


#include <thread>

#include <atomic>


int main()

{

    for (int iter = 0 ; iter < 20 ; ++iter)

    {

        std::atomic<int> num = { 0 };

        std::thread t1([&] {

            for (int i = 0 ; i < 10000000 ; ++i)

            {

                ++num;

                --num;

            }

        });

        std::thread t2([&] {

            for (int i = 0 ; i < 10000000 ; ++i)

            {

                num = 100;

            }

        });


        t2.join();

        t1.join();

        std::cout << num << std::endl;

    }

}

樣本輸出:


99

99

99

99

99

100

99

99

100

100

100

100

99

99

100

99

99

100

100

99


查看完整回答
反對 回復 2019-06-16
?
BIG陽

TA貢獻1859條經(jīng)驗 獲得超6個贊

沒有許多復雜的指示,如add DWORD PTR [rbp-4], 1很像CISC的風格。

它執(zhí)行三種操作:從內(nèi)存加載操作數(shù)、增量操作數(shù)、將操作數(shù)存儲回內(nèi)存。
在這些操作期間,CPU獲取并釋放總線兩次,在任何其他代理之間也可以獲得總線,這違反了原子性。

AGENT 1          AGENT 2load X              
inc C
                 load X
                 inc C
                 store X
store X

x只增加一次。


查看完整回答
反對 回復 2019-06-16
  • 3 回答
  • 0 關注
  • 774 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網(wǎng)微信公眾號