当 Interlocked 类可用时,为什么在 .NET 中使用 SyncLocks 进行简单操作?

发布于 2024-08-27 01:56:38 字数 560 浏览 5 评论 0原文

我已经在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

童话 2024-09-03 01:56:38

你是对的;这里应该使用 Interlocked,并且会比 SyncLock 更快。​​
然而,Interlocked 类并不为人所知。

但是,在某些情况下,您需要使用 SyncLock,而 Interlocked 则无济于事。

You're correct; Interlocked should be used here, and will be faster than SyncLock.
However, the Interlocked class is not well-known.

However, there are situations where you need to use SyncLock and Interlocked will not help.

清旖 2024-09-03 01:56:38

这是因为没有人知道这一点。传播这个词!

This is because no one knows about it. Spread the word!

維他命╮ 2024-09-03 01:56:38

简短的回答是因为使用 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 and lock { } 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 the volatile 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 without SyncLock.

伤痕我心 2024-09-03 01:56:38

我曾经读过一篇关于所谓的非原子和原子(在 VB 中:互锁)操作的非常好的解释,并将尝试对其进行总结。

Normal "non-atomic" operations consist of several steps 

->其他线程可以在这些 strep 之间工作

"Atomic" operations consist of one only one step 

->在处理原子操作时,其他线程无法执行工作,原子操作始终作为整体进行处理。

互锁类是此类原子操作的集合,因此根据定义是线程安全的。
即使多个线程对同一个变量执行读写操作,这些操作也是绝对线程安全的。

这些线程安全命令的组合仍然可能不安全,因为原子操作之间可能会出现竞争条件。

因此,如果您想要比较 2 个变量,然后递增较小的一个,则即使它们本身的单个操作是(interlocked.compare、interlocked.increment),这也不是线程安全的。
这里你仍然需要使用同步锁。

除了该限制之外,互锁没有“隐藏的坏面”。

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 都是假设的,线程安全解决方案

这里发布的所有问题都可以通过将这个简单的示例应用于有问题的代码来解决。

希望这对其他搜索该主题的人有所帮助。
贾尼斯

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.

Normal "non-atomic" operations consist of several steps 

-> other threads can work in between those streps

"Atomic" operations consist of one only one step 

-> 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:

 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

option 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

or option 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

or option 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

With interlocked.increment:

option 1:

T1 step 1: read 5, add 1, write 6
T2 step 1: read 6, add 2, write 8

or option 2:

T2 step 1: read 5, add 2, write 7
T1 step 1: read 7, add 1, write 8

-> 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

最近可好 2024-09-03 01:56:38

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文