atomic用法

memory orderhtml

源碼變成可執行程序,通常由預編譯,編譯,彙編,連接。源碼重排序通常分爲編譯期重排序和運行期重排序。node

編譯期重排序:編譯器在不改變單線程程序的語義的前提下,能夠從新安排語句的執行順序。在不改變程序的語義的前提下,儘量減小寄存器的讀取,存儲次數,充分複用寄存器的存儲值。ios

CPU亂序執行c++

 

名稱 語義               
memory_order_relaxed Relaxed語義
memory_order_consume Release-Acquire語義
memory_order_acquire Release-Acquire語義
memory_order_release  Release-Acquire語義
memory_order_acq_rel  Release-Acquire語義
memory_order_seq_cst  Sequential consistency語義

 

 

 

 

 

 

 

synchronizes-with、happens-before關係編程

synchronizes-with: 若是線程A存儲一個值,而線程B讀取該值,那麼線程A中的存儲和線程B的載入之間存在一種synchronizes-with關係併發

happens-before: 若是一個操做排在另一個操做以前,那麼該操做就該發生於另外一個操做以前app

 

Relaxed語義函數

最寬鬆的內存操做約定,不會保證修改會不會及時被其餘的線程看到,也不對亂序作任何要求性能

relaxed的原子類型操做不參與synchronizes-with關係。ui

不一樣變量的relaxed能夠被自由的重排,前提它們服從全部約束下的happens-before關係

#include <atomic>
#include <thread>
#include <assert.h>

atomic<bool> x, y;
atomic<int> z;

void write_x_then_y() 
{
     x.store(true, memory_order_relaxed);  
     y.store(true, memory_order_relaxed);
}

void read_y_then_x()
{
     while (!y.load(memory_order_relaxed));
     if (x.load(memory_order_relaxed)) 
          ++z;
}int main()
{
     x = false;
     y = false;
     z = 0;
     thread a(write_x_then_y);
     thread b(read_y_then_x);
     a.join();
     b.join();
     assert(z.load() != 0); // z可能等於0
}

 

Release-Acquire語義Sequential consistency語義

  release和acquire老是一塊兒使用

  release用於寫操做,acquire用於讀操做

  release以前的寫操做不容許亂序到release以後, acquire以前的讀操做不容許亂序到acquire以前

  acquire的修改會及時被release看到

Sequential consistency語義

  sequential consistency 至關於 release + acquire 以外,還加上了一個對該操做加上全局順序的要求

#include <atomic>
#include <thread>
#include <assert.h>

atomic<bool> x, y;
atomic<int> z;

void write_x() 
{
     x.store(true, memory_order_seq_cst);  
}

void write_y()
{
     y.store(true, memory_order_seq_cst);
}

void read_x_then_y()
{
     while (!x.load(memory_order_seq_cst));
     if (y.load(memory_order_seq_cst)) 
          ++z;
}

void read_y_then_x()
{
     while(!y.load(memory_order_seq_cst));
     if (x.load(memory_order_seq_cst))
          ++z;
}

int main()
{
     x = false;
     y = false;
     z = 0;
     thread a(write_x);
     thread b(write_y);
     thread c(read_x_then_y);
     thread d(read_y_then_x);
     a.join();
     b.join();
     c.join();
     d.join();
     assert(z.load() != 0); // z不可能等於0
}

 

store,load

atomic<bool> x, y;  
atomic<int> z;

void write()
{
    x.store(true, memory_order_relaxed);
    y.store(true, memory_order_release); // x的值比y先填充值
}


void read()
{
    while(!y.load(memory_order_acquire)); // y在等write值得填充
    if (x.load(memory_order_relaxed)) {
        z++;
    }
}

int main()
{
    x = false;
    y = false;
    z = 0;

    thread t1(write);
    thread t2(read);
    t1.join();
    t2.join();

    cout << "z: " << z << endl;
}

 

exchage

compare_exchange_weak

bool compare_exchange_weak(T& expected, T val, memory_order sync = memory_order_seq_cst) 

NOTE:

1. atomic變量的值與expected進行比較, 若是結果true, 用val更新atomic的值(like store); 若是結果爲false, 用atomic的值更新expected的值.

2. 這個函數能得到這個atomic變量的值,而且若是比較的結果是true的話就修改這個值. 整個操做是原子操做,在讀取或者修改這個值得瞬間,其餘的線程不會修改這個值.

3. memory_order 是否生效也是根據比較的結果,若是結果爲true,那麼生效,不然不生效

4. compare_exchage_weak容許僞失敗(fail spuriously),儘管expected值確實和atomic變量的值相等,仍然會返回false; 這須要使用while操做

#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
using namespace std;

struct Node {
    int value;
    Node *next;
};

atomic<Node*> list_head(nullptr);
void Append(int val)
{
    Node *p_old_node = list_head;
    Node *p_new_node = new Node {val, p_old_node};

    while (!list_head.compare_exchange_weak(p_old_node, p_new_node)) {
        p_new_node->next = p_old_node;
    }
}

int main()
{
    vector<thread> threads;
    for (int i = 0; i < 10; i++) {
        threads.push_back(thread(Append, i));
    }

    for (auto &i : threads) {
        i.join();
    }

    for (Node *it = list_head; it != nullptr; it = it->next) {
        cout << it->value << " ";
    }
    cout << endl;
}

 

compare_exchange_strong

bool compare_exchange_strong (T& expected, T val, memory_order sync = memory_order_seq_cst)

1. compare_exchange_strong的用法和compare_exchange_weak基本用法都同樣

2. compare_exchange_strong不容許僞失敗(fail spuriously)

3. compare_exchange_weak的循環結構在某些機器上可能有更好的性能

atomic<int> ai;
int tst_val = 4;
int new_val = 5;
bool exchanged = false;

void valsout()
{
    cout << "ai: " << ai << " tst_val: " << tst_val << " new_val: " << new_val << " exchanged: " << boolalpha << exchanged << endl;
}


int main()
{
    ai = 3;
    valsout(); //ai = 3, tst_val = 4, new_val = 5, exchanged = false;

    exchanged = ai.compare_exchange_strong(tst_val, new_val);
    valsout();  //ai = 3, tst_val = 3, new_val = 5, exchanged = false;

    exchanged = ai.compare_exchange_strong(tst_val, new_val);
    valsout();  //ai = 3, tst_val = 3, new_val = 5, exchanged = false;
}

 

 

參考資料:

[1] http://www.cplusplus.com/reference/atomic/atomic/

[2] <<c++併發編程>>

[3] http://www.cnblogs.com/haippy/p/3252056.html

[4] http://www.cnblogs.com/muhe221/articles/5049474.html

相關文章
相關標籤/搜索