atomic 內存序

提高性能的一種方式  atomic 替換mutex

內存序跟原子操作本身並不衝突, 不論用那種內存序該原子還是原子操作

atomic內存序: 就是來指定順序的

例子:

注 : 像類似 memory_order_relaxed 都是以函數爲單位來重新排執行指令的 [這個註釋後面再來看好了]
#include <atomic>
atomic<int> a (0);
atomic<int> b(0);
unsigned int __stdcall thread_write(void *ar){
    int hahah = 123;                             //1
    int balala = hahah;                         //2
    a.store(1,std::memory_order_relaxed);        //3
    b.store(666,std::memory_order_relaxed);        //4
    bool ooo = false;                         //7
    return 0;
}
unsigned int __stdcall thread_read(void * arg){

    while(b.load(std::memory_order_relaxed) != 666); //5
    int r = a.load(std::memory_order_relaxed);        //6
    cout << "a : " << r << endl;
    assert( r ==1 );

    return 0;
}
int main(int argc, char* argv[])
{
    HANDLE  t1  = (HANDLE)_beginthreadex(0,0,thread_read,0,0,0);
    HANDLE  t2  = (HANDLE)_beginthreadex(0,0,thread_write,0,0,0);
    while(1){
        Sleep(1000);
    }
    cout << "main done" << endl;
    return 0;
}

memory_order_relaxed 隨意的順序 , 怎麼個意思呢?

thread_write 中 1,2 是固定的, 3,4,7可以隨意,即 1,2, 3,4,7  / 1,2,4,3,7 / 7,4,3,1,2  等

thread_read 中 5,6 隨意

因此,thread_read中的 6 在弱內存模型中【意思是把指令重排,提高並行能力 => 編譯器乾的】 不一定是 1 ,可以是0,或者1;

比如 thread_read 中 a.load 將先執行,  thread_write還沒開始,則 a == 0;

那麼如何保證寫的順序呢?    memory_order_release 

如果你熟悉多線程,那麼可以這麼理解:

lock() -> 做一些事 -> unlock() ->  (  ReleaseSemaphore 或者 sem_post) 

如果不熟悉多線程, 那麼就從字面意思理解好了, release 相當於生成一個release 版本的程序, 即前面的該有的操作都完成了才 

能生成一個release 版本;

代碼:  修改 thread_write

unsigned int __stdcall thread_write(void *ar){
    int hahah = 123;                        //1
    a.store(1,std::memory_order_relaxed);   //2

    //修改這裏
    b.store(666,std::memory_order_release);  //3
    return 0;
}

 

memory_order_release 的意思是 1,2 隨意,但不能放到我後面, 到我這,你們前面的該執行該完成都得搞完;

到此, thread_read 函數能夠保證正確嗎? 

unsigned int __stdcall thread_read(void * arg){
    while(b.load(std::memory_order_relaxed) != 666);
    int r = a.load(std::memory_order_relaxed);
    assert( r ==1 );
    return 0;
}

很不幸, 不能!

memory_order_release 在thread_write 函數中保證了執行指令的順序

thread_read 中並沒有任何保證;   a.load 還是有可能被先執行;

相當於 :

1. a.load 

2. while( b.load() )

接下來就是輪到   memory_order_acquire 這個東西; 修改一行代碼即可;

unsigned int __stdcall thread_read(void * arg){
    while(b.load(std::memory_order_acquire) != 666);
    int r = a.load(std::memory_order_relaxed);
    assert( r ==1 );
    return 0;
}

意思是, 此處的指令 編譯器你別給我亂動,就按這個順序來.

如果熟悉mutex, 就把此處當 lock 即可;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章