2010-02-17 67 views
1

我正在使用以下代碼來限制資源的使用。使用信號量來保護隊列的問題

偶爾(成功運行3-4天后)我得到隊列空異常或返回的對象被發現爲空。

我想知道如果我限制只有5個線程進入這個Get方法,怎麼會發生這種情況。

調用GetConnection的地方,ReleaseConnection也在Finally塊中被明確調用。

隨着每次通話,我也記錄號碼。的隊列中的資源。隊列計數似乎永遠不會超過5.我的問題是,我需要使用鎖定/監視器同步訪問隊列(資源實例)嗎?

回答

3

缺省情況下,標準.NET集合都不是線程安全的。他們不能同時訪問沒有某種內存屏障阻止併發訪問。

在你的情況下,可以防止信號五年多線程訪問resources沒有什麼能夠阻止任何這五個併發線程從在同一時間進入Dequeue()Enqueue()。在那些導致隊列損壞的線程中發生罕見的競爭條件是完全可能的。你應該真的鎖定resources隊列本身。

我還建議您在鎖內執行測試以確保隊列中仍有要刪除的項目,然後再嘗試撥打Dequeue()。但是,由於我不知道代碼的具體工作方式,因此我會將其留給您來決定是否相關。

Semaphore smphSync = new Semaphore(0, 5); 
Queue<IResource> resources; 
private _lockObj = new object(); 

private IResource GetResource() 
{ 
    smphSync.WaitOne(); 
    lock(_lockObj) 
    { 
     IResource res = resources.Dequeue(); 
     return res; 
    } 
} 

private ReleaseResource(IResource res) 
{ 
    lock(_lockObj) 
    { 
     resources.Enqueue(res); 
    } 
    smphSync.Release(); 
} 
+0

太棒了!我很欣賞你的代碼。我完成了完全相同的代碼,似乎在過去幾天工作。只是想確定我沒有造成不必要的爭論。 StackOverflow岩石。 – cdpnet

+1

對於那些有興趣的人,從.NET 4開始,框架包含System.Collections.Concurrent命名空間中的一些線程安全集合(http://msdn.microsoft.com/zh-cn/library/system.collections.concurrent% 28VS.100%29.aspx)。這包括一個無鎖線程安全隊列(ConcurrentQueue)。 – jeffora

+2

@cdpnet:你有理由相信爭用是一個問題嗎?滿足時鎖通常只是昂貴的。我會永遠鎖定,只有當性能測試顯示爭用實際上是一個真正的問題時,我甚至會考慮嘗試一個無鎖解決方案。 –

1

我在我的ThreadSafeQueue類中添加了lock(),並最近添加了TryDequeue()方法。更多詳情,請參閱this post。絕對改進了多次線程碰撞,我之前經常看到(最明顯的是當Queue中沒有空值時返回空對象)。

編輯:檢查TryDequeue()方法並更新鏈接到正確的變更集。

+0

謝謝。其實,我正面臨着完全相同的結果。 我已經加了鎖,就像LBushkin說的那樣。似乎工作。想要得到更好的理解。 – cdpnet

+1

@cdpnet:不用擔心。他的解決方案肯定會有幫助我的課程將提供相同的保護(更多使用TryDequeue()方法),而無需在任何地方重新編碼鎖。可能不是您提供的示例中的問題,但稍後可能會派上用場:-) –