C# 用C语言实现同步算法#

C# 用C语言实现同步算法#,c#,.net,multithreading,synchronization,thread-safety,C#,.net,Multithreading,Synchronization,Thread Safety,我试图用C#实现同步算法,但没有成功 为什么下面的代码不是线程安全的 using System; using System.Threading; namespace SoftwareLockTest { class Program { private static volatile bool _isLocked1 = false; private static volatile bool _isLocked2 = false; p

我试图用C#实现同步算法,但没有成功

为什么下面的代码不是线程安全的

using System;
using System.Threading;

namespace SoftwareLockTest
{
    class Program
    {
        private static volatile bool _isLocked1 = false;
        private static volatile bool _isLocked2 = false;
        private static volatile int _count = 0;

        static void Main(string[] args)
        {
            Thread thread2 = new Thread(Thread2Work);
            thread2.Start();

            Thread1Work();
        }

        public static void Thread1Work()
        {
            while (true)
            {
                _isLocked1 = true;

                while (_isLocked2)
                {
                    _isLocked1 = false;
                    while (_isLocked2) ;
                    _isLocked1 = true;
                }

                CriticalSection();
                _isLocked1 = false;
            }
        }

        public static void Thread2Work()
        {
            while (true)
            {
                _isLocked2 = true;

                while (_isLocked1)
                {
                    _isLocked2 = false;
                    while (_isLocked1) ;
                    _isLocked2 = true;
                }

                CriticalSection();
                _isLocked2 = false;
            }
        }

        private static void CriticalSection()
        {
            if (_count != 0)
            {
                Console.WriteLine("NOT THREAD SAFE 1");
                _count = 0;
            }

            _count++;

            if (_count != 1)
            {
                Console.WriteLine("NOT THREAD SAFE 2");
            }

            _count--;

            if (_count != 0)
            {
                Console.WriteLine("NOT THREAD SAFE 3");
            }
        }
    }
}

嗯,现在还不完全清楚你想用锁标志做什么,理解代码对于线程来说是非常关键的,但是在没有锁的情况下,我希望看到大量的增量(
.increment
)/减量的
互锁(
.Decrement
)/test(
.compareeexchange
)。仅仅因为它是
易失性的
,并不意味着在执行
++
/
-
时两个线程不会被绊倒


但坦率地说,除非你有充分的理由不这样做,否则我只会使用
锁。你想保持简单——“显然没有bug”,而不是“没有明显bug”。

为什么不简单地使用
锁呢

lock (_anyInstantiatedObject)
{
    CriticalSection();
}

这样,您就可以依靠操作系统来确保没有其他线程同时进入关键部分。

我仍在努力解决这个问题,很明显,通常您确实应该使用锁……但我怀疑问题在于,
volatile
可能并不是您认为应该使用的

我想你会认为这意味着“当我写入这个变量时,立即使写入可见;当我从这个变量读取时,读取一个绝对最新的值”。(不管MSDN怎么说,事实上是我自己的线程教程;当我对它有了更好的处理时,我需要更新它)


我会看看我是否能准确地计算出发生了什么,但它看起来确实很奇怪。我想我理解你的代码试图做什么,而且我还没有在对波动性做出“简单”假设时打破它…(我已经重现了这个问题,这总是很有帮助的)

问题是,写入后再读取可能会被重新排序(即使使用“volatile”)。您需要在四个“while(_isLockedX)”循环前面调用Thread.MemoryBarrier()

请阅读有关内存障碍和易失性的解释


对于任何真正的项目,请选择现有的锁实现,而不是尝试自己的锁实现。

有趣的是,几小时前codeguru上也出现了同样的查询……下面是我的回答,从那里改编而来,但重点是你需要一个内存围栏来让代码正常工作

代码的问题在于它依赖于系统的顺序一致性。x86系统不是SC。它们被称为处理器一致性

这非常微妙,所以让我们稍微简化一下代码:

thread1:

WRITE _isLocked1, 1
READ _isLocked2
(skip the while loop)
critical section
WRITE _isLocked1, 0

thread2:

WRITE _isLocked2, 1
READ _isLocked1
(skip the while loop)
critical section
WRITE _isLocked2, 0
处理器一致性仅表示thread1按照执行顺序观察线程2所做的写入(因此写入1然后写入0)。相反,线程2对线程1的写入的观察。让你头疼的是处理器一致性并没有说明线程1的写入与线程2的写入是如何交错的,只是保持了依赖操作的因果关系(这对您的示例并不重要)


AMD文档第2卷第7.2节中有一组很好的例子,可以帮助您了解它,并参考Dekker的算法以及为什么它需要x86系统上的内存限制。

您正在尝试实现。不幸的是,他生活在一个比较简单的时代,那时硬件设计师和软件工程师仍在与每个人交谈另外,个人电脑行业厂商之间的激烈竞争,强调速度和核心,注定了德克尔先生的独创性的失败。有点高兴,我肯定已经对该算法进行了几十次审查,从来没有感到头痛过


好吧,这有点像元。看一下“便条”在那篇维基百科文章中,你可以看到为什么该算法不再有效。你可以找到很多可行的替代方案。关键是,你所发现的关于5年以上并发性的文献已经不再相关了。

这可能是一个很好的解释,但对于真正的工作,你应该使用监视器和锁。这不是家庭作业,它只是在试验“CriticalSection”在锁中受保护-线程方法中的“while(_isLockedX)”循环实现了一个自旋锁。问题是他的自旋锁实现有一个bug(缺少内存障碍)。很公平,我对你的(更具洞察力)进行了投票回答,但我将把这个问题留在这里,因为我认为它仍然提出了一些对“长尾”可能有用的有效观点。他不是在写汇编程序,而是在写C#。在这方面,.NET内存模型恰好与x86内存模型相匹配。对于其他处理器(例如IA-64),则.NET运行时将根据需要插入额外的屏障等,以便在这些处理器上模拟.NET内存模型。您的ASM代码在具有单处理器(单核)的x86系统上是正确的-但他的C#代码在.NET内存模型中仍然不正确。编译器也可能重新排序指令。谢谢,Thread.MemoryBarrier();解决了问题。我做了一些基准测试,发现它的工作速度是内置锁的2倍。哪个内置锁?System.Threading.SpinLock与您的实现最相似。lock(){}有额外的开销,因为它会在等待释放锁时使线程处于休眠状态。此外,您的实现可能会导致性能问题-旋转循环不断访问内存总线,从而降低其他处理器的速度。调用thread.SpinWait()在循环中,让处理器等待一段时间,然后再进行下一次内存访问。在.NET 4.0中,System.Threading.SpinWait将帮助您旋转(指数后退,如果短旋转还不够,则使线程进入睡眠状态)。此外,thread.SpinWait将告诉处理器它正在旋转(暂停asm指令,请参阅),提高了超线程处理器的性能。