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
什么时候应该?;不应该';我使用这个C#实用程序类通过联锁控制线程_C#_Multithreading_Interlocked_Spinlock_Multiprocessor - Fatal编程技术网

什么时候应该?;不应该';我使用这个C#实用程序类通过联锁控制线程

什么时候应该?;不应该';我使用这个C#实用程序类通过联锁控制线程,c#,multithreading,interlocked,spinlock,multiprocessor,C#,Multithreading,Interlocked,Spinlock,Multiprocessor,我试图理解这个类是如何编写的,以及何时应该和不应该使用它。如有任何见解,将不胜感激 internal struct SpinLock { private volatile int lockHeld; private readonly static int processorCount; public bool IsHeld { get { return this.lockHeld != 0;

我试图理解这个类是如何编写的,以及何时应该和不应该使用它。如有任何见解,将不胜感激

internal struct SpinLock
{
    private volatile int lockHeld;

    private readonly static int processorCount;

    public bool IsHeld
    {
        get
        {
            return this.lockHeld != 0;
        }
    }

    static SpinLock()
    {
        SpinLock.processorCount = Environment.ProcessorCount;
    }

    public void Enter()
    {
        if (Interlocked.CompareExchange(ref this.lockHeld, 1, 0) != 0)
        {
            this.EnterSpin();
        }
    }

    private void EnterSpin()
    {
        int num = 0;
        while (this.lockHeld != null || Interlocked.CompareExchange(ref this.lockHeld, 1, 0) != 0)
        {
            if (num >= 20 || SpinLock.processorCount <= 1)
            {
                if (num >= 25)
                {
                    Thread.Sleep(1);
                }
                else
                {
                    Thread.Sleep(0);
                }
            }
            else
            {
                Thread.SpinWait(100);
            }
            num++;
        }
    }

    public void Exit()
    {
        this.lockHeld = 0;
    }
}
内部结构自旋锁
{
私人锁;
私有只读静态int processorCount;
公共场所
{
得到
{
返回此。锁定!=0;
}
}
静态自旋锁()
{
SpinLock.processorCount=Environment.processorCount;
}
公开作废输入()
{
if(联锁比较交换(参考此锁定,1,0)!=0)
{
这是EnterSpin();
}
}
私有空间
{
int num=0;
while(this.lockhold!=null | | Interlocked.CompareExchange(参考this.lockhold,1,0)!=0)
{
如果(num>=20 | | SpinLock.processorCount=25)
{
睡眠(1);
}
其他的
{
睡眠(0);
}
}
其他的
{
Thread.SpinWait(100);
}
num++;
}
}
公共无效出口()
{
这个。锁定=0;
}
}
更新:我在源代码中找到了一个示例用法。。。这说明了如何使用上面的对象,尽管我不明白“为什么”

内部类FastReaderWriterLock
{
私人SpinLock myLock;
私家女服务员;
私人女服务员;
私人业主;
私有事件WaitHandle readEvent;
私有事件WaitHandle writeEvent;
公共FastReaderWriterLock()
{
}
公共无效收单机构ReaderLock(整数毫秒)
{
this.myLock.Enter();
而(this.owners<0 | | this.numWriteWaiters!=0)
{
如果(this.readEvent!=null)
{
this.WaitOnEvent(this.readEvent,ref this.numReadWaiters,毫秒计时);
}
其他的
{
this.LazyCreateEvent(参考this.readEvent,false);
}
}
FastReaderWriterLock FastReaderWriterLock=此;
fastReaderWriterLock.owners=fastReaderWriterLock.owners+1;
this.myLock.Exit();
}
私有void WaitOnEvent(eventwaithandlewaitevent,ref-uint numWaiters,int毫秒)
{
waitEvent.Reset();
uint&numpenter=numWaiters;
布尔标志=假;
this.myLock.Exit();
尝试
{
if(waitEvent.WaitOne(毫秒刺激,false))
{
flag=true;
}
其他的
{
抛出新的TimeoutException(“ReaderWriterLock超时已过期”);
}
}
最后
{
this.myLock.Enter();
uint&numPointer1=numWaiters;
如果(!标志)
{
this.myLock.Exit();
}
}
}
}
通常是一种锁的形式,它让等待的线程保持清醒(在一个紧密循环的检查条件下反复循环-想想“妈咪,我们到了吗?”),而不是依赖更重、更慢的内核模式信号。它们通常用于预期等待时间非常短的情况,在这种情况下,它们的性能优于为传统锁创建和等待操作系统句柄的开销。但是,与传统锁相比,它们会产生更多的CPU成本,因此在很短的等待时间内,最好使用传统锁(如类或各种实现)

上面的代码演示了这种短等待时间的概念:

waitEvent.Reset();
// All that we are doing here is setting some variables.  
// It has to be atomic, but it's going to be *really* fast
uint& numPointer = numWaiters;
bool flag = false;
// And we are done.  No need for an OS wait handle for 2 lines of code.
this.myLock.Exit();
有一个非常好的自旋锁,但是它只存在于v4.0+中,因此如果您使用的是较旧版本的.NET framework或从较旧版本迁移的代码,则可能有人编写了自己的实现

回答您的问题: 如果要在.NET 4.0或更高版本上编写新代码,则应使用内置的自旋锁。对于3.5或更高版本的代码,特别是如果您正在扩展Nesper,我认为此实现经过时间测试,是合适的。只在知道线程可能等待它的时间很短的情况下使用自旋锁,如上面的示例所示

编辑:看起来您的实现来自Nesper-Esper CEP库的.NET端口:


我可以证实,Nesper早在.NET framework 4之前就存在了,这就解释了为什么需要一个自转自旋锁。

看来,最初的作者想要一个更快版本的
ReaderWriterLock
。这门旧课慢得令人痛苦。我自己的测试(我很久以前做过)表明,RWL的开销大约是普通老式
锁的8倍
ReaderWriterLockSlim
改进了很多(尽管它的开销仍然是
lock
的2倍左右)。在这一点上,我想说放弃定制代码,只使用更新的
ReaderWriterLockSlim

但是,为了说明它的价值,让我解释一些定制的
SpinLock
代码

  • 联锁。CompareExchange
    是.NET版本的操作。它是最基本的同步原语。您可以从这个单一操作中构建所有其他内容,包括您自己的自定义
    监视器
    ——如类、读写器锁等。显然,这里使用它来创建旋转锁
  • Thread.Sleep(0)
    让位于任何处理器上具有相同或更高优先级的任何线程
  • Thread.Sleep(1)
    让位于任何处理器上的任何线程
  • Thread.SpinWait
    在指定的迭代次数内将线程放入紧循环中
尽管在您发布的代码中没有使用它,但还有另一种用于创建旋转锁(或o)的有用机制
waitEvent.Reset();
// All that we are doing here is setting some variables.  
// It has to be atomic, but it's going to be *really* fast
uint& numPointer = numWaiters;
bool flag = false;
// And we are done.  No need for an OS wait handle for 2 lines of code.
this.myLock.Exit();