这里的顺序一致性有什么问题?

What's wrong with sequental consistency here?

我正在研究 C 和 C++ 中的无锁算法,最近偶然发现了一个我不太理解的行为。如果你有下面的代码,运行 它会给你类似

reader started
writer started
iters=79895047, less=401131, eq=48996928, more=30496988

难道 std::atomics 不应该是顺序一致的吗?如果是这样,为什么 reader 有时会看到 ba 之前更新?我还尝试了各种涉及内存栅栏的技巧,但都没有成功。完整的可编译代码见 https://github.com/akamaus/fence_test

这个例子有什么问题?

std::atomic<uint> a(0);
std::atomic<uint> b(0);

volatile bool stop = false;

void *reader(void *p) {
    uint64_t iter_counter = 0;
    uint cnt_less = 0,
         cnt_eq = 0,
         cnt_more = 0;

    uint aa, bb;


    printf("reader started\n");

    while(!stop) {
        iter_counter++;
        aa = a.load(std::memory_order_seq_cst);
        bb = b.load(std::memory_order_seq_cst);
        if (aa < bb) {
            cnt_less++;
        } else if (aa > bb) {
            cnt_more++;
        } else {
            cnt_eq++;
        }
    }
        printf("iters=%lu, less=%u, eq=%u, more=%u\n", iter_counter, cnt_less, cnt_eq, cnt_more);

    return NULL;
}

void *writer(void *p) {
    printf("writer started\n");
    uint counter = 0;
    while(!stop) {
        a.store(counter, std::memory_order_seq_cst);
        b.store(counter, std::memory_order_seq_cst);
        counter++;
    }
}

顺序一致的内存排序意味着所有线程观察到的(用seq cst操作的原子对象的)修改顺序是一致的。该程序的行为就好像所有这些操作都交织在一个单一的总顺序中。考虑以下情况:


Writer Reader
       a == 0
a = 1
b = 1
       b == 1

结果:aa < bb.


Writer Reader
a = 1
       a == 1
       b == 0
b = 1

结果:aa > bb


带锁,例如a mutex,您可以确保操作不会交错。