C++ VC+中的自旋锁同步+;没有互斥
我有点迷路了。我相信我这里的是绝对线程安全的,但我不确定它是否是。我需要一个非常快速的自旋锁机制,用于优化线程锁定和释放的更复杂锁的一小部分(我需要创建一个更大的锁,它总是按照线程被阻止的顺序释放线程,这在mutex/EnterCriticalSection中是不会发生的)。然而,当涉及到使最小和最快的锁可能的时候,我真的不知道该怎么做C++ VC+中的自旋锁同步+;没有互斥,c++,multithreading,winapi,visual-c++,synchronization,C++,Multithreading,Winapi,Visual C++,Synchronization,我有点迷路了。我相信我这里的是绝对线程安全的,但我不确定它是否是。我需要一个非常快速的自旋锁机制,用于优化线程锁定和释放的更复杂锁的一小部分(我需要创建一个更大的锁,它总是按照线程被阻止的顺序释放线程,这在mutex/EnterCriticalSection中是不会发生的)。然而,当涉及到使最小和最快的锁可能的时候,我真的不知道该怎么做 class SpinGate { private: volatile LONGLONG key = 0; volatile LONGLONG g
class SpinGate
{
private:
volatile LONGLONG key = 0;
volatile LONGLONG gate = 1;
public:
void EnterGate();
void ExitGate();
};
void SpinGate::EnterGate()
{
LONGLONG myKey = InterlockedAdd64(&key, 1);
while (myKey != gate) {}
}
void SpinGate::ExitGate()
{
InterlockedAdd64(&gate, 1);
}
我认为我构建的这个东西将确保,即使100000000个线程试图在完全相同的时间获得一个密钥,它们都将获得一个不同的密钥,并因此被迫旋转直到它们的密钥出现。但是,当涉及到C++时,实现安全读取和写入到没有标准库对象的内存的机制,有些超出了我的知识范围。
我很好奇像“interlockedadd64”这样的函数是如何同时执行两个操作的,一个是递增操作,然后是读取操作,同时阻塞其他线程的。以及这是否始终是线程安全的
我认为我构建的这个东西将确保,即使100000000个线程试图在完全相同的时间获得一个密钥,它们都将获得一个不同的密钥,并因此被迫旋转直到它们的密钥出现
没有。C++ <代码> Value关键字不提供任何线程间的保证。
我很好奇像“interlockedadd64”这样的函数是如何同时执行两个操作的,一个是递增操作,然后是读取操作,同时阻塞其他线程的。以及这是否始终是线程安全的
它不会阻止其他线程。在现代CPU上,它只是在原子操作期间锁定缓存线,以便其他内核无法访问读写之间的内存位置。免责声明。我真的不鼓励开发人员编写自己的锁机制。大多数自定义锁实现都无法通过以下任何测试:
class SpinGate
{
private:
DWORD _dwOwnerThread;
LONG _ownerCount;
public:
SpinGate()
{
_dwOwnerThread = 0;
_ownerCount = 0;
}
void EnterGate()
{
LONG currentThread = (LONG)GetCurrentThreadId();
LONG result = 0;
bool owned = false;
// if we own the lock, just increment it
result = InterlockedCompareExchange(&_dwOwnerThread, currentThread, currentThread);
if (result == currentThread)
{
// we own the lock, so increment and exit
_ownerCount++;
owned = true;
}
// otherwise, spin
while (owned == false)
{
result = InterlockedCompareExchange(&_dwOwnerThread, currentThread, 0);
if (result == 0)
{
_ownerCount = 1;
owned = true;
}
else
{
while (_dwOwnerThread != 0)
{
__asm
{
pause;
}
}
}
}
return;
}
void ExitGate()
{
LONG currentThread = (LONG)GetCurrentThreadId();
LONG result = 0;
// if we don't own the lock, this is a developer error!
result = InterlockedCompareExchange(&_dwOwnerThread, currentThread, currentThread);
if (result != currentThread)
{
// ERROR - Caller attempted to exit a gate he didn't own
// ASSERT(FALSE);
return;
}
_ownerCount--;
if (_ownerCount == 0)
{
// give up the lock
result = InterlockedCompareExchange(&_dwOwnerThread, 0, currentThread);
}
return;
}
};
这个算法在我看来还可以。因为每次只添加1,所以可以使用
InterlockedIncrement()
。您的代码是否存在特定问题?如果只是一般性的反馈,你可能会在codereview上有更好的运气。@JonathanPotter我只是对这些函数不熟悉,我不确定我是否完全理解它们的工作原理。我的代码没有问题,但我不知道如果有我不了解的比赛条件,我必须给它多少电池才能得到有问题的碰撞。。。这是一个不确定“互锁”方法如何工作以及读取易变值是否总是安全的问题。e、 我不能直接测试错误,因为线程同步中的错误在产生冲突时是随机的。锁在Windows中是公平的。您需要阅读以了解使锁公平的后果。请注意,仍然有一些最佳的努力在进行中。您使用的VS版本是什么?如果是> 2013,为什么你不使用C++原子?Paolo:这实际上并不罕见,你不能锁定一个锁,你已经在自锁了。问题是,这是标签<代码> VisualC++<代码>,但是听起来像VS 2005 +(不是C++标准)实际上可以保证VisualStudio 2005的<代码>,编译器对易失性变量的读取操作使用获取语义,对易失性变量的写入操作使用释放语义。或者可能是我误读了。然后它进一步明确了这是特定于平台的。虽然有些人确实使用它,但我认为依赖它是相当疯狂的。(在那一页上也有很多写得不好、不精确和“胡言乱语”的迹象。我不会把它作为任何事情的主要来源。)(说到“特定平台”,我不是指Windows。我指的是一些未指明的“支持它”的CPU,不管这意味着什么。它可能意味着它什么也不做,只在碰巧以这种方式工作的CPU上工作。或者可能不工作。它太模糊了,很难说。)然后它说,“我们强烈建议您在处理跨线程共享的内存时,使用/volatile:iso以及显式同步原语和编译器内部函数。”所以,它说你有担保,然后强烈建议你不要依赖它,这似乎很奇怪。如果给你“保证”的一方说你不应该依赖它,我会说你不应该。遗憾的是,Windows上的内存模型缺乏文档记录。没有人知道他们能依靠什么或不能依靠什么,只是做别人做的和祈祷的事P@David在编写同步原语时,您不能再隐藏在抽象后面。你需要对金属进行编码。你旋转InterlockedCompareeExchange
。这在x86上是一场灾难,原因很多。首先,如果您与持有锁的线程共享一个物理内核,那么您将使其无法使用。另一方面,当您最终在性能最关键的时刻获得锁时,您将成为所有错误预测分支的母亲,并破坏管道。但是,对于业余爱好者来说,这仍然是一次很好的尝试但是,对于一个业余爱好者来说,这仍然是一次很好的尝试。也许这是你说过的最好的话,大卫在任何情况下,Windows线程调度程序仍将为