multithreading - 退出临界区

标签 multithreading x86 locking x86-64 mutual-exclusion

考虑多个线程并发执行以下代码:

long gf = 0;// global variable or class member

//...

if (InterlockedCompareExchange(&gf, 1, 0)==0) // lock cmpxchg
{
    // some exclusive code - must not execute in concurrent
    gf = 0; // this is ok ? or need
    //InterlockedExchange(&gf, 0); // [lock] xchg 
}

将上面的代码视为类似 C 的伪代码,这些代码将或多或少地直接转换为汇编,而无需对编译器优化(例如重新排序和存储消除)做出通常的让步。

因此,在某些线程独占获取标志 gf 之后 - 退出临界区是否足以写入一个零(如 gf = 0 中)或者这是否需要互锁 - InterlockedExchange(&gf, 0)?

如果两者都正常,假设多个内核同时调用 InterlockedCompareExchange(&gf, 1, 0) 的可能性很高,从性能角度来看哪个更好?

多个线程周期性地执行此代码(从几个地方,当某些事件触发时),重要的是下一个线程在释放后尽快再次进入临界区。

最佳答案

相关:Spinlock with XCHG解释为什么你不需要需要xchg释放 x86 asm 中的锁,只需一条存储指令。

但是在 C++ 中,您需要比普通 gf = 0; 更强大的东西在平原上 long gf变量。C/C++ 内存模型(对于普通变量)是非常弱排序的,即使在针对强排序的 x86 进行编译时也是如此,因为这对于优化至关重要。

您需要一个释放存储来正确释放锁,不允许临界区中的操作通过在编译时或运行时使用 gf=0 重新排序而泄漏出临界区。店铺。 http://preshing.com/20120913/acquire-and-release-semantics/ .

由于您使用的是 long gf , 不是 volatile long gf ,并且您没有使用编译器内存屏障,您的代码中没有任何内容可以阻止编译时重新排序。 (x86 asm 存储具有发布语义,因此我们需要担心的只是编译时重新排序。)http://preshing.com/20120625/memory-ordering-at-compile-time/


我们使用 std::atomic<long> gf; 尽可能便宜地获得我们需要的一切和 gf.store(0, std::memory_order_release); atomic<long>在支持 InterlockedExchange 的每个平台上都是无锁的, AFAIK,所以你应该可以混合搭配。 (或者只使用 gf.exchange() 获取锁。如果滚动你自己的锁,请记住你应该在只读操作上循环 + _mm_pause() 在等待锁时,不要用 xchg 敲打或 lock cmpxchg 并可能延迟解锁。请参阅 Locks around memory manipulation via inline assembly

这是 Why is integer assignment on a naturally aligned variable atomic on x86? 中警告的情况之一。你需要的 atomic<>确保编译器实际在您需要的地方/时间进行存储。

关于multithreading - 退出临界区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50221295/

相关文章:

java - Java SE 的 ManagedExecutorService、ManagedTask 和 ManagedTaskListener 替代方案

java - 2D volatile 数组 : will self-assignment help or do I need AtomicIntegerArray?

c - 它是如何工作的? pthread_cond_signal() 和 pthread_cond_wait()

c++ - 将单个 float 移动到 xmm 寄存器

linux - 用于 FS 在 x86 SMP 中启动的工作 linux 内核 + gem5 配置

windows - 锁定或解锁 Windows XP 时运行脚本

java - 如何理解Java Thread中的wait和notify方法?

linux - 多线程和 Sqlite - 数据库磁盘镜像格式错误

c - 在汇编中实现返回最大数和最小数之差的 C 函数

java - 自定义阻塞队列锁定问题