2012-10-02 42 views
0

我有一個對象,Product,存儲在我的應用程序的本地緩存中。這個產品緩存是使用一些ORM代碼從數據庫加載的,我不能輕易改變它。爲簡單起見,Product是:線程安全刷新後臺線程集合中對象的屬性

Public Class Product 
    Public Property ID as Integer 
    Public Property Name as String 
    Public Property Price as Decimal 
    Public Property Rank as Integer 
End Class 

產品存儲在本地緩存:

Public Class ProductList 
     Public Shared Function GetCache as List(Of Product) 
      Static _List as List(Of Product) 
      If _List is Nothing then 
       'Code to load Data and populate List from DB 
      End If 
      Return _List 
     End Function 
    End Class 

這在很大程度上簡化了,但你的想法。

Rank屬性是基於過去90天內所有銷售的未綁定計算字段,因此常見產品在搜索中顯示得更高。我想在後臺線程上生成排名 - 因爲它可能很耗時,並且不時刷新它。類似這樣的:

Public Sub UpdateRank 
    Dim dt as Datatable 
    dt = GetDataTable("exec usp_GetProductRank") 'Returns [ID, Rank] 
    For each row in dt.rows 
     _prod = getCache.getbyID(row.item(0)) 
     If _prod isnot Nothing then 
      _prod.rank = row.item(1) 
     End If 
    Next 
End Sub 

緩存可能會在更新等級時使用,導致髒讀,但我很樂意接受。我想要做的是以線程安全的方式執行此操作。也就是說,更新收藏而不必擔心是否添加和刪除了等。

我可以使用System.ComponentModel.BackgroundWorker執行此更新嗎?我在主UI中使用了很多線程來處理這樣的事情,但這是DLL中的非UI類。我正在考慮首先將緩存拉入Dictionary(of Integer, Product)

處理這個問題的最佳方法是什麼?

回答

1

當您使用對象的共享寫訪問時,您需要使用鎖或信號量來避免衝突。當這樣做的時候,它會告訴其他線程等待對象被解鎖。這不需要cpu資源。當對象被解鎖時,下一個線程可以按先來先服務的原則訪問它(理論上)。

F.ex:

VB.Net:

Class ThreadSafe 

    Private Shared _locker As Object = New Object 

    Private Shared Sub Go() 
     SyncLock _locker 
      If (_val2 <> 0) Then 
       Console.WriteLine((_val1/_val2)) 
      End If 
      _val2 = 0 
     End SyncLock 
    End Sub 
End Class 

C#:

class ThreadSafe 
{ 
    static readonly object _locker = new object(); 
    static int _val1, _val2; 

    static void Go() 
    { 
    lock (_locker) 
    { 
     if (_val2 != 0) Console.WriteLine (_val1/_val2); 
     _val2 = 0; 
    } 
    } 
} 

實施例來自於一個自由的電子書,其是在多線程很好的參考: http://www.albahari.com/threading/part2.aspx#_Locking

+0

太棒了,這個作品很棒,並且把我介紹給了這本書。謝謝。 backgroundWorker可以使用這個嗎? – Molloch

+0

不客氣.-)BackgroundWorker很好。 BGworker和前臺工作者之間的唯一區別是,主線程在退出時不會等待它(您可以調用BGworker上的Join()來解決此問題,或使用信號發送)​​。 – K3N

+1

如果你的意思是包裝'System.ComponentModel.BackgroundWorker'也沒關係(background-worker也用於引用線程「類型」)。 – K3N