Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ VC+中的自旋锁同步+;没有互斥_C++_Multithreading_Winapi_Visual C++_Synchronization - Fatal编程技术网

C++ VC+中的自旋锁同步+;没有互斥

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

我有点迷路了。我相信我这里的是绝对线程安全的,但我不确定它是否是。我需要一个非常快速的自旋锁机制,用于优化线程锁定和释放的更复杂锁的一小部分(我需要创建一个更大的锁,它总是按照线程被阻止的顺序释放线程,这在mutex/EnterCriticalSection中是不会发生的)。然而,当涉及到使最小和最快的锁可能的时候,我真的不知道该怎么做

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上,它只是在原子操作期间锁定缓存线,以便其他内核无法访问读写之间的内存位置。

免责声明。我真的不鼓励开发人员编写自己的锁机制。大多数自定义锁实现都无法通过以下任何测试:

  • 很少有家用brew实现试图保证有序的公平性。(一个以更高优先级运行的线程可能会使另一个线程无法获得锁)

  • 很难做到正确。甚至更难维护。当你有臭虫的时候,你会把头撞在墙上

  • 当一个简单的Windows锁就足够时,实际上并不需要

  • 但既然OP要求,我就试试看。你可能会喜欢。其他人可能会对它吹毛求疵

    在我的实现中,我添加了一些额外的工作,以允许同一线程递归地获取锁。我想你可以把这个拿出来,没事的

    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线程调度程序仍将为