2011-01-26 61 views
6

這是關於鎖定兩個List(Of T)對象的previous question的後續操作。答案很有幫助,但給我留下了另一個問題。使用SyncLock的正確方法(一般情況下)

假設我有這樣的功能:

Public Function ListWork() As Integer 
    List1.Clear() 
    ..Some other work which does not modify List1.. 
    List1.AddRange(SomeArray) 
    ..Some more work that does not involve List1.. 
    Retrun List1.Count 
End Function 

駐留在聲明列表1類。在多線程環境中,我現在明白我應該有一個用於List1的私有鎖定對象,並在修改或枚舉時鎖定List1。我的問題是,我應該這樣做:

Private List1Lock As New Object 
Public Function ListWork() As Integer 
    SyncLock List1Lock 
    List1.Clear() 
    End SyncLock 
    ..Some other work which does not modify List1.. 
    SyncLock List1Lock 
    List1.AddRange(SomeArray) 
    End SyncLock 
    ..Some more work that does not involve List1.. 
    SyncLock List1Lock 
    Dim list1Count As Integer = List1.Count 
    End SyncLock 
    Retrun list1Count 
End Function 

或本:

Private List1Lock As New Object 
Public Function ListWork() As Integer 
    SyncLock List1Lock 
    List1.Clear() 
    ..Some other work which does not modify List1.. 
    List1.AddRange(SomeArray) 
    ..Some more work that does not involve List1.. 
    Dim list1Count As Integer = List1.Count 
    End SyncLock 
    Retrun list1Count 
End Function 

我猜測,前者的例子是最優的?

回答

9

從這些例子中,很難判斷哪一個是正確的,如果是的話。一些指導方針/觀察雖然可以幫助你回答你的問題,或知道提供什麼額外的信息:

首先,你必須同步?每個線程都有一個這個類的實例會更有意義嗎?如果每個實例都是線程本地的,並且只在該線程上修改和使用,則不需要鎖定。

如果此類和利用線程的目的是爲了並行處理更大的數據集,主線程可能更合理地以某種邏輯方式劃分任務,然後等待工作線程完成。在這種情況下,請不要單獨管理線程,而應查看ThreadPool並等待句柄。大部分骯髒的工作都是爲你完成的。

關於通常的同步/鎖定:如果您的操作在步驟之間中斷,數據是否一致/有效?

在你的例子中,假設你有兩個線程。第一個是在.AddRange().Count之間的區域,當第二個線程出現時進入函數,並獲取列表中的鎖。

線程1運行多一點,並擊中守護.Count方法的鎖,然後進入睡眠狀態。在此期間,線程2清除列表,然後釋放其鎖,然後將線程1喚醒,然後獲取鎖。

在這種情況下,當線程1完成工作以構建列表時,線程1將從該函數返回0。然後,列表長度不會真的爲0,因爲線程2已經出現並填充了列表。

在這種情況下,各個列表操作周圍的鎖會破壞程序,所以在ClearCount調用之間圍繞一個鎖定更有意義。

簡而言之,多線程是引入與Race Conditions相關的一整類微妙錯誤的好方法,這通常會導致Heisenbugs

在可以的時候避免線程通常是明智的。如果你不能,嘗試以最小同步的方式來安排工作負載(例如,在開始時給線程一組數據,然後等待它發出完成信號,例如鏈接線程池示例)。如果你不能這樣做,那就小心行事,並且總是問自己:「如果兩條線在這個區域運行會發生什麼?」。

希望這可以幫助武裝你在多線程代碼中的未來冒險。

+0

我想我現在明白這一點。非常微妙。我應該參加一個課或其他...感謝您的洞察力。 – 2011-01-26 10:09:58

6

「這取決於」。 這兩個例子有不同的語義。

在後面的例子中,整套操作相對於鎖是原子的。在前面的例子中,雖然訪問列表被鎖定,但整套操作無法(正確)視爲原子(相對於鎖)。

想象一下,如果在不同的線程上調用ListWork對同一個對象的操作/線程交錯,將會發生什麼情況。

快樂編碼。

相關問題