2014-01-27 63 views
1

請注意以下幾點:以下示例使用Interlocked.CompareExchange是否需要揮發性和/或內存障礙?

private DateTime m_lastTimeUtc; 
private int m_isInProgress; 
... 
if (DateTime.UtcNow - m_lastTimeUtc >= m_interval) 
{ 
    if (Interlocked.CompareExchange(ref m_isInProgress, 1, 0) == 0) 
    { 
     if (DateTime.UtcNow - m_lastTimeUtc >= m_interval) 
     { 
      m_lastTimeUtc = DateTime.UtcNow; 
      // Do the work 
      m_lastTimeUtc = DateTime.UtcNow; 
      Interlocked.Exchange(ref m_isInProgress, 0); 
     } 
    } 
} 

這段代碼的目的語義如下:

  • 該代碼可以經常被引用 - 數百次。
  • 它應該或多或少地定期做某些工作。如果代碼沒有經常被調用,那麼實際的時間可能非常不規則,這是可以的。但如果它經常被調用(通常是這種情況),那麼這項工作就會經常進行。
  • 碰到m_isInProgress = 1的線程將跳過工作,它是完全沒問題的。

當然,環境是多線程的。

我注意到人們正在使用的關鍵字volatile和/或調用Interlocked.MemoryBarrier()做的事情類似,我在這裏做什麼的時候(或者至少看起來是這樣給我)。如果我知道我理解他們兩人是如何工作的,我會說謊。

有人可以解釋我是否需要他們在我的代碼,爲什麼?

P.S.

我有幾個地方重複相同的模式。所以,我要爲大家介紹以下方法:

private static void DoWork(TimeSpan interval, ref DateTime lastTimeUtc, ref int isInProgress, Action work) 
{ 
    if (DateTime.UtcNow - lastTimeUtc >= interval && Interlocked.CompareExchange(ref isInProgress, 1, 0) == 0 && DateTime.UtcNow - lastTimeUtc >= interval) 
    { 
     lastTimeUtc = DateTime.UtcNow; 
     work(); 
     lastTimeUtc = DateTime.UtcNow; 
     Interlocked.Exchange(ref isInProgress, 0); 
    } 
} 

鑑於這種方法,這是我想讓它被調用:

DoWork(m_interval, ref m_lastTimeUtc, ref m_isInProgress,() => 
{ 
    // Do the work 
}); 

請問答案是一樣的DoWork

回答