concurrency - 内存屏障与互锁操作

标签 concurrency mutex lock-free memory-barriers

我正在努力提高我对内存障碍的理解。假设我们有一个弱内存模型并且我们调整了 Dekker's algorithm .是否可以通过添加内存屏障使其在弱内存模型下正常工作?

我认为答案是否定的令人惊讶。原因(如果我是对的)是,尽管可以使用内存屏障来确保读取不会越过另一个,但它不能确保读取不会看到陈旧数据(例如缓存中的数据)。因此,它可以看到过去某个时间关键部分被解锁(根据 CPU 的缓存),但在当前时间其他处理器可能会看到它被锁定。如果我的理解是正确的,那么必须使用互锁操作,例如通常称为 test-and-set 或 compare-and-swap 的操作,以确保多个处理器之间的内存位置的值同步一致。

因此,我们是否可以正确地期望没有弱内存模型系统只会提供内存屏障?系统必须提供测试和设置或比较和交换等操作才能有用。

我意识到流行的处理器,包括 x86,提供的内存模型比弱内存模型强得多。请集中讨论弱内存模型。

(如果 Dekker 算法是一个糟糕的选择,如果可能,请选择另一种互斥算法,其中内存屏障可以成功实现正确的同步。)

最佳答案

您是对的,内存屏障无法确保读取看到最新值。它所做的是在单个线程上和线程之间强制执行操作之间的排序。

例如,如果线程 A 执行一系列存储,然后在最终存储到标志位置之前执行释放屏障,而线程 B 从标志位置读取,然后在读取其他值之前执行获取屏障,那么其他变量将有线程 A 存储的值:

// initially x=y=z=flag=0

// thread A
x=1;
y=2;
z=3;
release_barrier();
flag=1;

// thread B
while(flag==0) ; // loop until flag is 1
acquire_barrier();
assert(x==1);  // asserts will not fire
assert(y==2);
assert(z==3);

当然,你需要确保加载和存储到flag是原子的(如果变量适当对齐,简单的加载和存储指令在最常见的 CPU 上)。如果没有线程 B 上的 while 循环,线程 B 很可能会读取 flag 的陈旧值 (0)。 ,因此您不能保证为其他变量读取的任何值。

因此,栅栏可用于强制执行 Dekker 算法中的同步。

这是 C++ 中的示例实现(使用 C++0x 原子变量):

std::atomic<bool> flag0(false),flag1(false);
std::atomic<int> turn(0);

void p0()
{
    flag0.store(true,std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_seq_cst);

    while (flag1.load(std::memory_order_relaxed))
    {
        if (turn.load(std::memory_order_relaxed) != 0)
        {
            flag0.store(false,std::memory_order_relaxed);
            while (turn.load(std::memory_order_relaxed) != 0)
            {
            }
            flag0.store(true,std::memory_order_relaxed);
            std::atomic_thread_fence(std::memory_order_seq_cst);
        }
    }
    std::atomic_thread_fence(std::memory_order_acquire);

    // critical section


    turn.store(1,std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_release);
    flag0.store(false,std::memory_order_relaxed);
}

void p1()
{
    flag1.store(true,std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_seq_cst);

    while (flag0.load(std::memory_order_relaxed))
    {
        if (turn.load(std::memory_order_relaxed) != 1)
        {
            flag1.store(false,std::memory_order_relaxed);
            while (turn.load(std::memory_order_relaxed) != 1)
            {
            }
            flag1.store(true,std::memory_order_relaxed);
            std::atomic_thread_fence(std::memory_order_seq_cst);
        }
    }
    std::atomic_thread_fence(std::memory_order_acquire);

    // critical section


    turn.store(0,std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_release);
    flag1.store(false,std::memory_order_relaxed);
}

如需完整分析,请参阅我的博客条目 http://www.justsoftwaresolutions.co.uk/threading/implementing_dekkers_algorithm_with_fences.html

关于concurrency - 内存屏障与互锁操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3304801/

相关文章:

c++ - 无锁队列中的内存管理

java - 外部同步LinkedHashmap

linux - linux' "mutex lock"是使用 "memory barrier"实现的吗?

java - 通过单独的锁保证锁定每个值

C++11增加原子变量,赋值给其他值,是原子操作吗?

c++ - 有 C++11 临界区吗?

multithreading - 自旋锁是免费的吗?

assembly - 加载-获取/存储-释放和中断

multithreading - 没有并发怎么能有并行呢?

java - 一个线程完成任务后,如何告诉线程池中的其他线程停止?