VB.NET 2010,.NET 4
大家好,
我的问题是,想象一下我有两个List(Of T)对象和多线程环境中的一个子程序来修改这两个对象。我不太了解锁,所以我不确定我是否可以做:
SyncLock CType(List1, IList).SyncRoot
List1.Clear()
List2.Clear()
End SyncLock
或者我必须:
SyncLock CType(List1, IList).SyncRoot
SyncLock CType(List2, IList).SyncRoot
List1.Clear()
List2.Clear()
End SyncLock
End SyncLock
?任何见解?我是否走在正确的轨道上?任何意见将不胜感激。
非常感谢,Brian
答案 0 :(得分:7)
首先,锁定非私有对象是不好的做法,因为其他东西可能锁定它,然后事情从那里走下坡路,而不是锁定私有成员对象,如
Class Class1
Private lockObject as New Object
Public Sub Clear()
SyncLock lockObject
...
End Synclock
End Sub
End Class
现在,对于实际问题:除非您执行的每个操作都修改了两个列表(可疑),否则每个列表应该有一个锁。虽然可以使用一个锁定对象来表示“我正在使用列表执行某些操作”,但阻止另一个不与您运行在同一列表中的线程中的方法没有多大意义,并且只会减慢放下一切。
因此,简而言之:每组锁使用一个锁对象(用于在list1上操作的锁,用于列表2的锁等)。对于在两个列表上运行的部分,它的代码稍微多一些,但代码的性能会更高。
另外,作为一般说明:保持锁定的时间尽可能短。你花在锁上的时间越少,另一个线程出现的可能性就会越小,并且在你完成之前就会被阻塞。
MSDN Page on SyncLock也许值得一读,它包含了这些信息和一些例子。并且@BasicLife是正确的,始终确保在任何地方以相同的顺序获取锁。
整个框架中的一般规则,除非您访问类上的静态成员,除非另有说明,否则它不是线程安全的。所以当在列表上操作时,你会想要在列表上添加,删除,清除或枚举时锁定,我确定还有其他的,但这些是最常见的。
答案 1 :(得分:4)
为了扩展Matt的答案,请确保在需要多个锁的情况下以相同的顺序锁定对象
如果你在Method1
:
Lock List 1
Lock List 2
Release 2
Release 1
并在Method2
中执行:
Lock List 2
Lock List 1
Release 1
Release 2
然后你可以得到一个死锁情况,如果两个方法被不同的线程同时调用,你可以得到这个:
thread 1 on Method1 locks list 1
thread 2 on Method2 locks list 2
thread 1 on Method1 waits until list 2 is released
thread 2 on Method2 waits until list 1 is released
Threads 1 and 2 are now deadlocked and eventually one or both will be killed off