本文介绍了退出关键区域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

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

Consider several threads executing concurrently the following code:

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伪代码进行处理,将其或多或少地直接转换为汇编语言,而无需对编译器优化(例如重新编排和消除存储)进行通常的让步.

Treat the code above as C-like pseudo-code, which will be translated more-or-less directly into assembly without the usual concessions to compiler optimizations such as re-odering and store elimination.

因此,在某个线程专门获取标志gf-以从关键区域退出后,是否足以写入零(如gf = 0中所示)还是需要互锁-InterlockedExchange(&gf, 0)?

So after some thread exclusively acquires flag gf- to exit from the critical region is it enough to write a zero (as in gf = 0) or does this need to be interlocked - InterlockedExchange(&gf, 0)?

如果两个都没问题,那么从性能的角度来看,这是更好的选择,假设几个内核并发调用InterlockedCompareExchange(&gf, 1, 0)的可能性很高?

If both are OK, which is better from a performance view, assuming that with high probability that several cores concurrently call InterlockedCompareExchange(&gf, 1, 0)?

几个线程会定期执行此代码(某些事件触发时会从多个地方执行该代码),重要的是下一个线程在释放后尽快再次进入关键区域.

Several threads periodically execute this code (from several places, when some events fire) and it is important that the next thread again enters the critical region as soon as possible after it freed.

推荐答案

相关:使用XCHG的自旋锁解释了为什么您不需要只需xchg来释放x86 asm中的锁,而只是一条存储指令.

Related: Spinlock with XCHG explains why you don't need xchg to release a lock in x86 asm, just a store instruction.

但是在C ++中, 在普通的long gf变量上需要比普通的gf = 0;强的东西. C/C ++内存模型(用于普通变量)即使对于强顺序的x86进行编译,它的顺序也非常微弱,因为这对于优化是必不可少的.

But in C++, you need something stronger than a plain gf = 0; on a plain long gf variable. The C / C++ memory model (for normal variables) is very weakly ordered, even when compiling for strongly-ordered x86, because that's essential for optimizations.

您需要一个释放存储库来正确释放锁,而不会通过在编译时或运行时使用gf=0存储库重新排序来使关键部分中的操作泄漏出关键部分. http://preshing.com/20120913/acquire-and-release-semantics/.

You need a release-store to correctly release a lock, without allowing operations in the critical section to leak out of the critical section by reordering at compile time or runtime with the gf=0 store. http://preshing.com/20120913/acquire-and-release-semantics/.

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

Since you're using long gf, not volatile long gf, and you aren't using a compiler memory barrier, nothing in your code would prevent compile-time reordering. (x86 asm stores have release semantics, so it's only compile-time reordering we need to worry about.) 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(),请不要随意敲击xchglock cmpxchg并可能延迟解锁.请参见内存周围的锁通过内联汇编进行操作.

We get everything we need as cheaply as possible using std::atomic<long> gf; and gf.store(0, std::memory_order_release); atomic<long> is lock-free on every platform that supports InterlockedExchange, AFAIK, so you should be ok to mix and match. (Or just use gf.exchange() to take the lock. If rolling your own locks, keep in mind that you should loop on a read-only operation + _mm_pause() while waiting for the lock, don't hammer away with xchg or lock cmpxchg and potentially delay the unlock. See Locks around memory manipulation via inline assembly.

这是,您需要atomic<>来确保编译器确实在需要的地方存储/.

This is one of the cases where the warning in Why is integer assignment on a naturally aligned variable atomic on x86? that you need atomic<> to make sure the compiler actually does the store where / when you need it applies.

这篇关于退出关键区域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-07 02:53