[英]what makes c++ atomic atomic
我只知道,即使代碼int64_t_variable = 10
也不是原子操作。 例如
int64_t i = 0;
i = 100;
在另一個線程(例如T2)中,它可能讀取的值不是0
或100
。
std::atomic<int64_t> i; i.store(100, std::memory_order_relaxed)
std::atomic<int64_t> i; i.store(100, std::memory_order_relaxed)
是原子的。 那么,基於Q1,原子使用了什么魔術來實現它呢? v = n
,我怎么知道它是否是原子的? 例如,如果v為void *
,它是否是原子的? =================================
更新:在我的問題:當T2讀取i
,0和100都適合我。 但任何其他結果都不合理。 這就是重點。 因此,我認為CPU緩存或編譯器之類的功能無法實現這一目標。
以上是真的嗎?
是。 如果您不使用同步( std::atmoic<>
, std::mutex
,...),那么您在一個線程中所做的任何更改都不能被假定為在其他線程中顯示。 甚至可能是編譯器優化了某些東西,因為它無法改變功能。 例如
bool flag = true;
void stop_stuff()
{
flag = false;
}
void do_stuff()
{
while (flag)
std::cout << "never stop";
}
由於flag
沒有同步,因此編譯器可以自由地假設它永遠不會更改,甚至可以在循環條件下檢查標志。 如果這樣做,那么無論您調用stop_stuff
多少次, do_stuff
都將永遠不會結束。
如果將標志更改為std::atomic<bool> flag
,則編譯器無法再做出這樣的假設,因為您告訴它此變量可以在函數范圍之外更改,因此需要對其進行檢查。
請注意,當您有多個線程共享數據並且其中至少有一個線程寫入共享數據時,不提供同步稱為數據競爭,並且按照標准,這是未定義的行為。 上面的示例只是這種未定義行為的可能結果之一。
std::atomic<int64_t> i; i.store(100, std::memory_order_relaxed)
std::atomic<int64_t> i; i.store(100, std::memory_order_relaxed)
是原子的。 那么,基於Q1,原子使用了什么魔術來實現它呢?
它要么使用系統提供的原子基元,要么使用諸如std::mutex
類的鎖定機制來保護訪問。
我一直認為處理少於64位的任何操作都是原子操作(假設64位cpu),看來我錯了。 所以對於v = n,我怎么知道它是否是原子的? 例如,如果v為void *,它是否是原子的?
盡管這在某些系統上可能是正確的,但對於C ++內存模型卻並非如此。 唯一原子的是std::atomic<T>
。
是。 原因包括“它需要多個指令”,“內存緩存可能會使其混亂”和“如果您未提及該變量可能在其他地方更改,則編譯器可能會做出令人驚訝的事情(aka UB)”。
上面的原因都需要處理, std::atomic
為編譯器/ C ++庫實現提供執行此操作的信息。 不允許編譯器進行任何意外的優化,它可能會在必要時發出緩存刷新,並且實現可能使用鎖定機制來防止對同一對象的不同操作發生交織。 請注意,並非所有這些都是必需的:x86內置了一些原子性保證。您可以使用std::atomic::is_always_lockfree
告知自己是否給定的std::atomic
類型在您的平台上始終是無鎖的,以及是否給定實例是無鎖的 (由於例如對齊/未對齊訪問)。
如果不使用std::atomic
,則由於上述原因,您將沒有原子性保證。 在CPU的指令級上,它可能是原子的,但是C ++是在沒有此類保證的抽象機器上定義的。 如果您的代碼依賴抽象計算機上的原子性,但未能指定此原子性,則編譯器可能會進行無效的優化並生成UB。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.