屏障实现代码从顺序一致性转宽松内存序的正确性验证
简易Barrier实现的内存序修改正确性验证
我在《C++ Concurrency in Action》中看到一段无法使用C17的std::experimental::barrier或C20的std::barrier时可用的简易屏障实现。这种屏障的同步逻辑是:一组线程可以调用wait等待,或调用done_waiting退出线程组;当所有线程到达屏障时,屏障会重置;若有线程退出,线程组的大小会相应缩减。
原作者Anthony Williams为了便于逻辑推导,采用了顺序一致性内存序,同时提到可以改用更宽松的内存序来提升效率。我对代码做了修改,修改后的代码如下:
struct barrier { std::atomic<unsigned> count; std::atomic<unsigned> spaces; std::atomic<unsigned> generation; barrier(unsigned count_):count(count_),spaces(count_),generation(0) {} void wait(){ unsigned const gen=generation.load(std::memory_order_acquire); if(1 == spaces.fetch_sub(1, std::memory_order_relaxed)){ spaces=count.load(std::memory_order_relaxed); generation.fetch_add(1, std::memory_order_release); }else{ while(generation.load(std::memory_order_relaxed)==gen){ std::this_thread::yield(); } } } void done_waiting(){ count.fetch_sub(1, std::memory_order_relaxed); if(1 == spaces.fetch_sub(1, std::memory_order_relaxed)){ spaces=count.load(std::memory_order_relaxed); generation.fetch_add(1, std::memory_order_release); } } };
我的推理逻辑是:generation的递增操作使用std::memory_order_release内存序,和wait中generation的load(std::memory_order_acquire)操作形成同步关系,确保count到spaces的赋值操作对读取到新generation值的线程可见;spaces的其他读写修改(RMW)操作属于释放序列的一部分,可以采用std::memory_order_relaxed内存序。
我写了一段测试代码做初步验证,表面上运行正常,但不确定这个修改和我的推理是否正确,有没有遗漏的同步问题?
测试代码如下:
void fun(barrier* b){ std::cout << "In Thread " << std::this_thread::get_id() << std::endl; b->wait(); std::cout << std::this_thread::get_id() << " First wait done" << std::endl; b->wait(); std::cout << std::this_thread::get_id() << " Second wait done" << std::endl; b->done_waiting(); } int main(){ barrier b{2}; std::thread t(fun, &b); fun(&b); std::cout << std::this_thread::get_id() << " " << b.get_count() << std::endl; t.join(); }
内容的提问来源于stack exchange,提问作者user17799869
相关产品推荐
相关产品推荐

