当 Interlocked 类可用时,为什么在 .NET 中使用 SyncLocks 进行简单操作?
我已经在 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 方法完成同样的事情时,我是否有理由使用专用锁定对象来滚动自己的锁定?
I've been doing simple multi-threading in VB.NET for a while, and have just gotten into my first large multi-threaded project. I've always done everything using the Synclock
statement because I didn't think there was a better way.
I just learned about the Interlocked
Class - it makes it look as though all this:
Private SomeInt as Integer
Private SomeInt_LockObject as New Object
Public Sub IntrementSomeInt
Synclock SomeInt_LockObject
SomeInt += 1
End Synclock
End Sub
Can be replaced with a single statement:
Interlocked.Increment(SomeInt)
This handles all the locking internally and modifies the number. This would be much simpler than writing my own locks for simple operations (longer-running or more complicated operations obviously still need their own locking).
Is there a reason why I'd rolling my own locking, using dedicated locking objects, when I can accomplish the same thing using the Interlocked
methods?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
你是对的;这里应该使用
Interlocked
,并且会比SyncLock
更快。然而,
Interlocked
类并不为人所知。但是,在某些情况下,您需要使用
SyncLock
,而Interlocked
则无济于事。You're correct;
Interlocked
should be used here, and will be faster thanSyncLock
.However, the
Interlocked
class is not well-known.However, there are situations where you need to use
SyncLock
andInterlocked
will not help.这是因为没有人知道这一点。传播这个词!
This is because no one knows about it. Spread the word!
简短的回答是因为使用
Monitor
锁(VB 中的SyncLock
和 C# 中的lock { }
)不仅可以确保只有一个线程处于同一状态。 time 可以访问该变量(或者,从严格意义上讲,一次只有一个线程可以获得锁定对象上的锁),但它也会创建确保对变量的读取不会被优化掉所需的内存屏障。如果您从不简单地读取变量的值(换句话说,您的所有工作都是通过调用 Interlocked 完成的),那么您就可以了。但是,如果您需要能够对变量执行正常读取,那么情况会更加复杂。无锁读/写通常在 C# 中使用
volatile
关键字来完成。这指示编译器在使用变量的任何地方读取该变量的值,而不是将这些读取中的任何读取优化到本地缓存中。不幸的是,VB.NET 中没有类似的工具,因此您必须使用其他工具。此问题的接受答案应该提供一些有关您可以做什么的更多信息。简而言之,大多数人在 VB.NET 中使用 SyncLock,因为它比没有
SyncLock
时所需的逻辑更容易且更简单。The short answer is because using a
Monitor
lock (SyncLock
in VB andlock { }
in C#) not only assures that only one thread at a time can access the variable (or, in a strict sense, only one thread at a time can obtain a lock on the locking object), but it also creates the memory barrier required to ensure that reads on the variable aren't optimized away.If you're never simply reading the value of the variable (in other words, all of your work is done through calls to
Interlocked
), then you'll be OK. However, if you need to be able to perform a normal read of the variable then the situation is more complicated. Lockless reads/writes are usually accomplished in C# using thevolatile
keyword. This instructs the compiler to read the value of the variable everywhere it's used, rather than optimizing away any of these reads into a local cache. Unfortunately there is no equivalent in VB.NET, so you'll have to use something else.The accepted answer to this question should provide some more information on what you can do. In short, most people use
SyncLock
in VB.NET because it's easier and less complicated than the logic required to do it withoutSyncLock
.我曾经读过一篇关于所谓的非原子和原子(在 VB 中:互锁)操作的非常好的解释,并将尝试对其进行总结。
->其他线程可以在这些 strep 之间工作
->在处理原子操作时,其他线程无法执行工作,原子操作始终作为整体进行处理。
互锁类是此类原子操作的集合,因此根据定义是线程安全的。
即使多个线程对同一个变量执行读写操作,这些操作也是绝对线程安全的。
这些线程安全命令的组合仍然可能不安全,因为原子操作之间可能会出现竞争条件。
因此,如果您想要比较 2 个变量,然后递增较小的一个,则即使它们本身的单个操作是(interlocked.compare、interlocked.increment),这也不是线程安全的。
这里你仍然需要使用同步锁。
除了该限制之外,互锁没有“隐藏的坏面”。
a = 5 的竞争条件的一个示例:
选项 1:
或选项 2:
或选项 3:
使用 interlocked.increment:
选项 1:
或选项 2:
->在所有情况下 a = 8 都是假设的,线程安全解决方案
这里发布的所有问题都可以通过将这个简单的示例应用于有问题的代码来解决。
希望这对其他搜索该主题的人有所帮助。
贾尼斯
I once read a very good explanation on so called non-atomic and atomic (in VB: interlocked) operations and will try to sum that up.
-> other threads can work in between those streps
-> other threads cannot perform work while atomic operations are processed, atomic operations are always processed as whole
The interlocked class is a collection of such atomic operations and therefor threadsafe by definition.
Even with multiple threads performing read and write operations on the same variable, these operations are absolutely thread safe.
Still a combination of those threadsafe commands can be unsafe, as race conditions can occur in between the atomic operations.
So if you want to for example compare 2 variables and then increment the smaller one, this is not thread safe even though the single operations for themself are (interlocked.compare, interlocked.increment).
Here you still have to use synclocks.
Other than that limitation there is no "hidden bad side" of interlocked.
One example for a racecondition with a = 5:
option 1:
or option 2:
or option 3:
With interlocked.increment:
option 1:
or option 2:
-> in all cases a = 8 as supposed, threadsafe solution
All the questions that were posted here can be solved by applying this simple example to the questionable code.
Hope this helps other people who google this topic.
Janis
Interlocked
仅限于对整数、长整型和布尔值等的简单操作。例如,如果您想将一个项目添加到共享列表(T)中,您仍然需要
SynClock
。Interlocked
is limited to simple operations on Integer, Long and Boolean and such.If you want to add an item to a shared List(of T) for example, you will still need
SynClock
.