我正在使用以下代碼來限制資源的使用。使用信號量來保護隊列的問題
偶爾(成功運行3-4天后)我得到隊列空異常或返回的對象被發現爲空。
我想知道如果我限制只有5個線程進入這個Get方法,怎麼會發生這種情況。
調用GetConnection的地方,ReleaseConnection也在Finally塊中被明確調用。
隨着每次通話,我也記錄號碼。的隊列中的資源。隊列計數似乎永遠不會超過5.我的問題是,我需要使用鎖定/監視器同步訪問隊列(資源實例)嗎?
我正在使用以下代碼來限制資源的使用。使用信號量來保護隊列的問題
偶爾(成功運行3-4天后)我得到隊列空異常或返回的對象被發現爲空。
我想知道如果我限制只有5個線程進入這個Get方法,怎麼會發生這種情況。
調用GetConnection的地方,ReleaseConnection也在Finally塊中被明確調用。
隨着每次通話,我也記錄號碼。的隊列中的資源。隊列計數似乎永遠不會超過5.我的問題是,我需要使用鎖定/監視器同步訪問隊列(資源實例)嗎?
缺省情況下,標準.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();
}
我在我的ThreadSafeQueue類中添加了lock(),並最近添加了TryDequeue()方法。更多詳情,請參閱this post。絕對改進了多次線程碰撞,我之前經常看到(最明顯的是當Queue中沒有空值時返回空對象)。
編輯:檢查TryDequeue()方法並更新鏈接到正確的變更集。
謝謝。其實,我正面臨着完全相同的結果。 我已經加了鎖,就像LBushkin說的那樣。似乎工作。想要得到更好的理解。 – cdpnet
@cdpnet:不用擔心。他的解決方案肯定會有幫助我的課程將提供相同的保護(更多使用TryDequeue()方法),而無需在任何地方重新編碼鎖。可能不是您提供的示例中的問題,但稍後可能會派上用場:-) –
太棒了!我很欣賞你的代碼。我完成了完全相同的代碼,似乎在過去幾天工作。只是想確定我沒有造成不必要的爭論。 StackOverflow岩石。 – cdpnet
對於那些有興趣的人,從.NET 4開始,框架包含System.Collections.Concurrent命名空間中的一些線程安全集合(http://msdn.microsoft.com/zh-cn/library/system.collections.concurrent% 28VS.100%29.aspx)。這包括一個無鎖線程安全隊列(ConcurrentQueue)。 – jeffora
@cdpnet:你有理由相信爭用是一個問題嗎?滿足時鎖通常只是昂貴的。我會永遠鎖定,只有當性能測試顯示爭用實際上是一個真正的問題時,我甚至會考慮嘗試一個無鎖解決方案。 –