【问题标题】:atomic variable also require lock on read-modify-store operation?原子变量还需要锁定读取-修改-存储操作吗?
【发布时间】:2021-07-06 02:50:48
【问题描述】:

我知道原子变量是无锁的!!
它不会锁定线程,但我有一个问题..
像 std::atomic::fetch_add 这样的 Read-Modify-Store 操作也是原子执行的???
我认为这个操作不仅仅是一条指令。
它需要多个周期......所以如果我不锁定内存总线(实际上我不知道互斥锁是否包含内存总线锁),其他线程可以在读取和存储之间进行内存操作。
所以我认为即使原子变量也需要锁定......

我知道吗???

【问题讨论】:

标签: c++ multithreading atomic


【解决方案1】:

你知道的就在早期的 x86 架构中。

在x86架构中,提供了指令前缀LOCK。原子变量依赖于该指令。早期的LOCK是通过锁定一条总线来实现的,以防止其他CPU内核访问内存。可以想象,这种实现效率非常低

大部分x86处理器都支持CAS的硬件实现,保证了多处理器多核系统中原子操作的正确性。 CAS 的实现也不会锁定总线,只会阻止其他 CPU 访问检查相关内存的缓存块。 让你看看代码。 示例代码是:

#include <iostream>
#include <thread>
#include <atomic>
 
std::atomic<long long> data;
void do_work()
{
    data.fetch_add(1, std::memory_order_relaxed);
}
 
int main()
{
    std::thread th1(do_work);
    std::thread th2(do_work);
    std::thread th3(do_work);
    std::thread th4(do_work);
    std::thread th5(do_work);
 
    th1.join();
    th2.join();
    th3.join();
    th4.join();
    th5.join();
 
    std::cout << "Result:" << data << '\n';
}

将上面的代码转换成指令。在 gcc 8 中将 do_work 函数翻译成

        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], 1
        mov     DWORD PTR [rbp-12], 0
        mov     rax, QWORD PTR [rbp-8]
        mov     edx, OFFSET FLAT:data
        lock xadd       QWORD PTR [rdx], rax
        nop
        pop     rbp
        ret

使用lock xadd 确保原子操作符。

【讨论】:

  • The implementation of CAS also does not lock the bus and only blocks access by other CPUs to the cache blocks that check the associated memory. 这是关于 MESI 协议的吗??
  • 是的,cpu缓存锁定机制是基于MESI缓存一致性协议来实现的。
猜你喜欢
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 2022-01-12
  • 2017-06-11
  • 1970-01-01
  • 2016-05-20
  • 2012-04-23
  • 2023-03-24
相关资源
最近更新 更多