簡體   English   中英

使用Thread Safety更新單例的屬性

[英]Updating property of a singleton with Thread Safety

我們的設置是:Asp.NET + MVC5使用AutoFac進行DI。

我們有一個類(它是一個單例),它管理各種服務的訪問令牌。 時不時地,這些令牌過於接近到期(不到10分鍾),我們請求新令牌,刷新它們。 我目前的實現如下:

// member int used for interlocking
int m_inter = 0;

private string Token { get; set; }

private DateTimeOffset TokenExpiry { get; set; }

public SingletonClassConstructor()
{
   // Make sure the Token has some value.
   RefreshToken();
}

public string GetCredentials()
{
  if ((TokenExpiry - DateTimeOffset.UTCNow).TotalMinutes < 10)
  {
     if (Interlocked.CompareExchange(ref m_inter, 1, 0) == 0)
     {
        RefreshToken();
        m_inter = 0;
     }
  }

  return Token;
}

private void RefreshToken()
{
   // Call some stuff
   Token = X.Result().Token;
   TokenExpiry = X.Result().Expiry;
}

正如您所看到的,Interlocked確保只有一個線程通過,其余線程獲得舊令牌。 我想知道的是 - 我們能否最終處於一種奇怪的情況,即當令牌被覆蓋時,另一個線程試圖讀取而不是舊令牌,會得到部分搞砸的結果? 這個實現有什么問題嗎?

謝謝!

對我而言,此實現的最大問題是您可以在一個有效期內刷新令牌兩次或更多次。 如果線程在檢查到期條件之后但在CompareExchange()之前被CompareExchange() ,那么另一個線程可以在第一個線程恢復之前完成整個刷新操作,包括重置m_inter 這理論上可以發生在任意多個線程上。

您的代碼的其余部分不夠具體,無法發表評論。 沒有Token類型的聲明,因此不清楚這是一個struct還是class 並且您的GetCredentials()方法被聲明為返回Credentials值,而是返回Token值,因此代碼顯然甚至不是真正的代碼。

如果Token類型是一個class ,那么其余的實現可能就好了。 即使在x64平台上,也可以原子方式分配引用類型變量,因此檢索Token屬性值的代碼將看到舊令牌或新令牌,而不是某些損壞的中間狀態。 (當然,我假設Token對象本身是線程安全的,最好是因為它是不可變的。)

就個人而言,我不打擾CompareExchange() 只需使用完整的C# lock語句即可完成。 包含synchronized塊中的整個操作:檢查到期時間,必要時替換令牌,並從lock返回令牌值。

根據您展示的代碼,我認為將整個事物封裝在屬性本身並將其public更有意義。 但是不管怎樣,只要代碼檢索令牌值只能通過這部分同步代碼獲得它,證明代碼正確的最簡單,最可靠的方法就是使用lock 萬一你看到性能問題,那么你可以考慮更難以實現的替代實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM