2010-04-07 47 views
5

我有一個採樣的系統。我在應用程序中有多個客戶端線程對這些示例感興趣,但實際進行示例的過程只能在一個上下文中進行。它足夠快,可以阻止調用進程,直到完成採樣,但足夠慢,我不希望多個線程堆積請求。我想出了這個設計(精簡到最小的細節):這是一個正確的聯鎖同步設計嗎?

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 
    } 
} 

這是安全在我描述的場景使用?

回答

5

是的,它看起來很安全,因爲int這裏是一個原子類型。但我還是會建議用

private static object _samplingLock = new object(); 

和使用替代

private static int _isSampling; 

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

很簡單,因爲它是推薦的模式,也確保所有訪問_lastSample正確對待。

注:我期望可比較的速度,鎖使用內部使用Interlocked的託管Monitor類。

編輯:

我錯過了回退方面,這裏是另外一個版本:

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

+ 1爲更簡單的解決方案。 – 2010-04-07 21:36:43

+1

從維護角度來看,TryEnter可能更好,因爲與Interlocked.CompareExchange相比,大多數人可能會熟悉Monitor.TryEnter。在這種情況下,我並不擔心開銷,因爲我只是每秒採樣幾次。當它確實執行採樣時,我敢肯定,採樣過程本身的開銷將比鎖定基元多得多。 – 2010-04-07 21:56:34

+0

我喜歡Monitor.TryEnter,但是我們不應該使用ReaderWriterLockSlim這些天? http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim_members.aspx – 2010-04-07 21:57:12

-1

我通常聲明揮發性布爾和做類似:

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; 
} 
+1

無論如何,如果您只是在鎖內部使用它,則無需聲明bool volatile。此外,鎖定可變字段是一種非常糟糕的做法。在您的示例中,可能會同時輸入兩個鎖定塊。當你鎖定一個可變字段時,如果兩個(或者甚至更多)線程同時進入一個鎖定塊,我會期待一個關於爲什麼它不會傷害(那麼多)的詳細評論。 – 2011-04-18 08:53:46