【问题标题】:CPU Relax instruction and C++11 primitivesCPU 松弛指令和 C++11 原语
【发布时间】:2014-10-01 03:03:07
【问题描述】:

我注意到许多使用特定于操作系统的原语实现的无锁算法,例如here 描述的自旋锁(使用特定于 Linux 的原子原语)经常使用“cpu Relax”指令。使用 GCC,可以通过以下方式实现:

asm volatile("pause\n": : :"memory");

具体来说,这条指令经常用在while循环自旋锁的主体中,同时等待一个变量设置为某个值。

C++11 似乎没有提供任何可移植的“cpu_relax”类型指令。这有什么原因吗? “暂停”语句真的有什么用处吗?

编辑:

另外,我想问:为什么 C++11 标准委员会不决定包含一个通用的 std::cpu_relax() 或其他什么?便携性是不是太难保证了?

【问题讨论】:

  • @bames53,std::this_thread::yield 不是一回事。将 cpu 控制权交给线程调度程序。相反,cpu 放松概念指示 cpu 避免分支预测和其他各种事情。

标签: c++ multithreading gcc c++11 atomic


【解决方案1】:

PAUSE 指令是 x86 特定的。它的唯一用途是在自旋锁等待循环中,它:

提高自旋等待循环的性能。在执行“自旋等待循环”时,处理器在退出循环时将遭受严重的性能损失,因为它检测到可能的内存顺序违规。 PAUSE 指令向处理器提示代码序列是自旋等待循环。

还有:

在 spinwait 循环中插入暂停指令可大大降低处理器的功耗。

将此指令放在自旋锁循环中的位置也是 x86_64 特定的。我不能代表 C++11 标准人员,但我认为他们有理由得出结论,这种魔法的正确位置是在相关库中......以及实现原子、互斥锁等所需的所有其他魔法.

注意:PAUSE 确实释放处理器以允许另一个线程运行。它不是“低级”pthread_yield()。 (尽管在 Intel 超线程内核上,它确实可以防止自旋锁线程占用内核。)PAUSE 的基本功能似乎是关闭通常的指令执行优化和流水线,这会减慢线程速度(a位),但是发现锁很忙,这降低了访问锁变量的速率,因此当锁的当前所有者试图继续实际工作时,缓存系统不会被服务员敲打.

请注意,用于“手动滚动”自旋锁、互斥锁等的原语不是特定于操作系统的,而是特定于处理器的。

我不确定我是否会将“手卷”自旋锁描述为“无锁”!

FWIW,英特尔对自旋锁的建议(“英特尔® 64 和 IA-32 架构优化参考手册”)是:

  Spin_Lock:
    CMP   lockvar, 0     // Check if lock is free.
    JE    Get_lock
    PAUSE                // Short delay.
    JMP   Spin_Lock
  Get_Lock:
    MOV   EAX, 1
    XCHG  EAX, lockvar  // Try to get lock.
    CMP   EAX, 0        // Test if successful.
    JNE   Spin_Lock

很明显,可以使用std::atomic_flag... 或使用pthread_spin_lock() 来编写编译成这样的东西,在我的机器上是:

  pthread_spin_lock:
    lock decl (%rdi)
    jne    wait
    xor    %eax, %eax
    ret
  wait:
    pause
    cmpl   $0, (%rdi)
    jg     pthread_spin_lock
    jmp    wait

这很难出错,真的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多