我已经在VB.NET中进行了一段时间的简单多线程,并且刚刚进入我的第一个大型多线程项目。我总是使用Synclock
语句完成所有事情,因为我认为没有更好的方法。
我刚刚了解了Interlocked
类 - 它看起来好像这一切:
Private SomeInt as Integer
Private SomeInt_LockObject as New Object
Public Sub IntrementSomeInt
Synclock SomeInt_LockObject
SomeInt += 1
End Synclock
End Sub
可以用一个语句替换:
Interlocked.Increment(SomeInt)
这会在内部处理所有锁定并修改数字。这比为简单操作编写自己的锁要简单得多(更长时间运行或更复杂的操作显然仍然需要自己锁定)。
当我使用Interlocked
方法完成同样的事情时,我是否有理由使用专用锁定对象滚动自己的锁定?
答案 0 :(得分:9)
你是对的;此处应使用Interlocked
,并且速度会快于SyncLock
但是,Interlocked
类并不为人所知。
但是,在某些情况下,您需要使用SyncLock
而Interlocked
无效。
答案 1 :(得分:5)
这是因为没人知道。传播这个词!
答案 2 :(得分:4)
简短的回答是因为在VB中使用Monitor
锁定(SyncLock
和C#中的lock { }
)不仅可以确保一次只有一个线程可以访问变量(或者,从严格意义上讲,一次只有一个线程可以锁定锁定对象),但它也会创建所需的内存屏障,以确保不会优化对变量的读取。
如果你从不简单地读取变量的值(换句话说,你所有的工作都是通过调用Interlocked
完成的),那么你就行了。但是,如果您需要能够执行变量的正常读取,则情况会更复杂。无锁读/写通常使用volatile
关键字在C#中完成。这指示编译器在任何地方读取变量的值,而不是将任何这些读取优化到本地缓存中。不幸的是,在VB.NET中没有相应的东西,所以你必须使用别的东西。
this question的已接受答案应提供有关您可以执行的操作的更多信息。简而言之,大多数人在VB.NET中使用SyncLock
因为它比没有 SyncLock
的所需的逻辑更容易也更简单。
答案 3 :(得分:2)
我曾经读过一个关于所谓的非原子和原子(在VB中:互锁)操作的非常好的解释,并试图总结它。
Normal "non-atomic" operations consist of several steps
- >其他线程可以在这些链接之间工作
"Atomic" operations consist of one only one step
- >其他线程在处理原子操作时无法执行工作,原子操作总是作为整体处理
互锁类是这种原子操作的集合,因此根据定义线程安全。 即使多个线程对同一个变量执行读写操作,这些操作也绝对是线程安全的。
这些线程安全命令的组合仍然是不安全的,因为竞争条件可能发生在原子操作之间。
因此,如果您想比较2个变量然后递增较小的变量,即使它们自己的单个操作是(interlocked.compare,interlocked.increment),这也不是线程安全的。 在这里你仍然需要使用synclocks。
除了那个限制之外,没有互锁的“隐藏的坏方面”。
a = 5的竞赛条件的一个例子:
Thread1: a+=1
Thread2: a+=2
--> supposed to be 8, but can be only 6 or 7,
but can also be 6 or 7 depending on which thread wins the race
选项1:
T1 step 1: read 5
T1 step 2: add 1 = 6
T1 step 3: write 6
T2 step 1: read 6
T2 step 2: add 2 = 8
T2 step 3: write 8
--> is 8 as supposed
或选项2:
T1 step 1: read 5
T2 step 1: read 5
T1 step 2: add 1 = 6
T2 step 2: add 2 = 7
T2 step 3: write 7
T1 step 3: write 6
--> is only 6
或选项3:
T1 step 1: read 5
T2 step 1: read 5
T1 step 2: add 1 = 6
T2 step 2: add 2 = 7
T1 step 3: write 6
T2 step 3: write 7
--> is only 7
使用interlocked.increment:
选项1:
T1 step 1: read 5, add 1, write 6
T2 step 1: read 6, add 2, write 8
或选项2:
T2 step 1: read 5, add 2, write 7
T1 step 1: read 7, add 1, write 8
- >在所有情况下a = 8作为假设的线程安全解决方案
这里发布的所有问题都可以通过将这个简单的例子应用于可疑代码来解决。
希望这可以帮助其他谷歌这个主题的人。 贾尼斯
答案 4 :(得分:1)
Interlocked
仅限于对Integer,Long和Boolean等的简单操作。
例如,如果要将项目添加到共享列表(T),您仍需要SynClock
。