这是一个正确的互锁同步设计吗?

时间:2010-04-07 21:23:12

标签: c# synchronization multithreading locking interlocked

我有一个带样品的系统。我在应用程序中有多个对这些示例感兴趣的客户端线程,但是获取Sample的实际过程只能在一个上下文中进行。它足够快,它可以阻止调用过程,直到完成采样,但足够慢,我不希望多个线程堆积请求。我想出了这个设计(剥离到最小的细节):

public class Sample
{
    private static Sample _lastSample;
    private static int _isSampling;

    public static Sample TakeSample(AutomationManager automation)
    {
        //Only start sampling if not already sampling in some other context
        if (Interlocked.CompareExchange(ref _isSampling, 0, 1) == 0)
        {
            try
            {
                Sample sample = new Sample();
                sample.PerformSampling(automation);
                _lastSample = sample;
            }
            finally
            {
                //We're done sampling
                _isSampling = 0;
            }
        }

        return _lastSample;
    }

    private void PerformSampling(AutomationManager automation)
    {
        //Lots of stuff going on that shouldn't be run in more than one context at the same time
    }
}

在我描述的场景中使用它是否安全?

2 个答案:

答案 0 :(得分:5)

是的,它看起来很安全,因为int在这里是原子类型。但我仍然建议更换

private static int _isSampling;

private static object _samplingLock = new object();

并使用:

lock(_samplingLock)
{
    Sample sample = new Sample();
    sample.PerformSampling(automation);
   _lastSample = sample;
}

只是因为它是推荐的模式,并且还确保正确处理对_lastSample的所有访问。

注意:我希望速度可比,lock使用内部使用Interlocked的托管Monitor类。

修改

我错过了后退方面,这是另一个版本:

   if (System.Threading.Monitor.TryEnter(_samplingLock))
   {
     try
     {
         .... // sample stuff
     }
     finally
     {
          System.Threading.Monitor.Exit(_samplingLock);
     }
   }

答案 1 :(得分:-1)

我通常会声明一个不稳定的bool并做类似的事情:

private volatile bool _isBusy;
private static Sample _lastSample;

private Sample DoSomething()
{
     lock(_lastSample)
     {
       if(_isBusy)
          return _lastSample;
       _isBusy = true;
     }

     try
     {
       _lastSample = new sameple//do something
     }
     finally
     {
        lock(_lastSample)
        {
           _isBusy = false;
        }
     }
     return _lastSample;
}