在我阅读第5章中的C ++并发后,我尝试编写一些代码来测试我对内存排序的理解:
#include <iostream>
#include <vector>
#include <thread>
#include <atomic>
std::atomic<int> one,two,three,sync;
void func(int i){
while(i != sync.load(std::memory_order_acquire));
auto on = one.load(std::memory_order_relaxed); ++on;
auto tw = two.load(std::memory_order_relaxed); ++tw;
auto th = three.load(std::memory_order_relaxed); ++th;
std::cout << on << tw << th << std::endl;
one.store(on,std::memory_order_relaxed);
two.store(tw,std::memory_order_relaxed);
three.store(th,std::memory_order_relaxed);
int expected = i;
while(!sync.compare_exchange_strong(expected,i+1,
std::memory_order_acq_rel))
expected = i;
}
int main(){
std::vector<std::thread> t_vec;
for(auto i = 0; i != 5; ++i)
t_vec.push_back(std::thread(func,i));
for(auto i = 0; i != 5; ++i)
t_vec[i].join();
std::cout << one << std::endl;
std::cout << two << std::endl;
std::cout << three << std::endl;
return 0;
}
我的问题是:本书说memory_order_release和memory_order_acquire应该是一对来正确读取正确的值。
因此,如果func()的第一行在带有memory_order_acquire的循环中加载同步,它应该会破坏该对并在同步时产生不可预测的错误。
然而,正如预期的那样,它在我的x86平台上编译后打印:
111
222
333
444
555
5
5
5
结果显示没问题。所以我只是想知道func()中发生了什么(虽然我自己写了......)?
已添加:根据第141页的操作中的C ++并发代码:
#include <atomic>
#include <thread>
std::vector<int> queue_code;
std::atomic<int> count;
void populate_queue(){
unsigned const number_of_items = 20;
queue_data.clear();
for(unsigned i = 0; i < number_of_items; ++i)
queue_data.push_back(i);
count.store(number_of_items, std::memory_order_release);
}
void consume_queue_items(){
while(true){
int item_index;
if((item_index=count.fetch_sub(1,memory_order_acquire))<=0){
wait_for_more_items();
continue;
}
process(queue_data[item_index-1]);
}
}
int main(){
std::thread a(populate_queue);
std::thread b(consume_queue_items);
std::thread c(consume_queue_items);
a.join();
b.join();
c.join();
}
无论谁首先访问计数,线程b和线程c都可以正常工作。这是因为:
值得庆幸的是,第一个fetch_sub()确实参与发布 序列,因此store()与第二个fetch_sub()同步。两个消费者线程之间仍然没有同步关系 链中可以有任意数量的链接,但如果它们都是读取 - 修改 - 写入操作,例如fetch_sub(),则store()仍将与标记为memory_order_acquire的每个链接同步。在此示例中,所有链接是相同的,并且都是获取操作,但它们可能是具有不同memory_ordering语义的不同操作的混合。
但我找不到相关的相关信息,如何读取 - 修改 - 写操作如fetch_sub()参与发布序列?如果我将其更改为使用memory_order_acquire加载,那么store()是否仍会在每个独立线程中与load()同步?