2017-01-04 27 views
2

假設我有C++中的結構和類:多線程原子儲存在碳多重值/負載++

struct Vec { 
    double x; 
    double y; 
    double z; 
} 

class VecTracker { 
    Vec latest_vec; 
    std::atomic<double> highest_x; 
    std::atomic<double> highest_y; 
    std::atomic<double> highest_z; 

    //updates highest_x, highest_y, highest_z atomically 
    void push_vec(const Vec& v); 
    double get_high_x() const; 
    double get_high_y() const; 
    double get_high_z() const; 
    //returns Vec consisting of snapshot of highest_x, highest_y, highest_z 
    Vec get_highs() const; 
} 

我得[R讀線程和一個寫線程。作者線程將更新零個或多個highest_*成員。如果讀者線程調用get_highs(),則需要讀寫器線程讀取highest_x,highest_y等以產生向量,來自當前調用寫入器線程push_vec()函數的所有寫入對於讀取器線程可見,對於讀取器線程

現在,我知道如果Vec足夠小,我可以使用std::atomic<Vec>。問題是,如果它太大,則不能使用這些存儲/加載的本機CPU指令。是否有任何方法可以使用std::atomic_thread_fence來保證在讀取器線程拾取它之前多個原子寫入由寫入器線程提交?也就是說,保證在讀者線程看到它們之前,寫入器線程的所有寫入操作都會被提交。還是std::atomic_thread_fence只提供線程內的重新排序保證?目前,僅爲每個成員使用.store(std::memory_order_release)似乎並不能保證所有三個商店都在任何閱讀之前發生。

很顯然,我可以在這裏使用鎖,但理想情況下我想找到一種方法來使此數據結構無鎖定。

我知道我可以將highest_x,highest_yhighest_z放在一個結構中,並在堆上分配它的兩個副本,在每次寫入後自動交換指針。這是唯一的方法嗎?

回答

4

魔鬼在這裏://updates highest_x, highest_y, highest_z atomically。你如何保證它們確實是原子的?由於3雙打不符合16B(我在X86_64平臺上了解的最大原子操作),唯一的方法就是使用mutex

你的問題不在籬笆上。通過發佈fence指令,您將保證所有以前的更新都可見。但你不能保證的是,他們不會在之前看到這個。因此,您將能夠讀取其中一個矢量變量的更新值。

要解決您的問題,您應該使用mutex - 它們在無爭用時非常高效 - 或者,如果您對互斥過敏,則使用您自己描述的指針交換解決方案。

+0

啊哈。是的,我認爲只有本地的原子操作實際上可以保證原子行爲。看起來指針交換是當時的方式。 這裏不能真正使用Mutex或螺旋鎖,因爲會有非常大的爭用,我想保證進度。 – alfalfasprout

+0

我搜索了,但找不到任何對CMPXCHG32B指令的引用。如果這樣的指令實際存在,在這種情況下就足夠了,因爲在今天的大多數系統中,三倍只能達到24B。你有沒有把它與CMPXCHG16B混淆?在那種情況下,你的觀點更有意義。 –

+0

@ErikNyström,100%是!感謝您的發現。 – SergeyA