Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 为什么需要锁来实现只读int属性?_.net_Multithreading_Locking - Fatal编程技术网

.net 为什么需要锁来实现只读int属性?

.net 为什么需要锁来实现只读int属性?,.net,multithreading,locking,.net,Multithreading,Locking,我是线程新手,我在一个应用程序中访问了一个自定义线程池实现示例。我只是粘贴代码的必要部分: Public Class ThreadPool Private CountLock As New Object Private _Count As Integer Public ReadOnly Property ThreadCount() As Integer Get SyncLock CountLock Return _C

我是线程新手,我在一个应用程序中访问了一个自定义线程池实现示例。我只是粘贴代码的必要部分:

Public Class ThreadPool

    Private CountLock As New Object
    Private _Count As Integer

    Public ReadOnly Property ThreadCount() As Integer
      Get
         SyncLock CountLock
           Return _Count
         End SyncLock
      End Get
    End Property

    Public Sub Open()
      Interlocked.Increment(_Count)
    End Sub

    Public Sub Close()
      Interlocked.Decrement(_Count)
      ....
    End Sub

EndClass

我的问题是,为什么我们需要一个锁来实现readonly ThreadCount属性?

这没有意义,因为在修改属性时没有锁。可能代码以前没有使用联锁操作,甚至在打开/关闭时也在使用SyncLock?在这种情况下,读取访问中也确实需要SyncLock。

此代码应用于访问属性getter中的值。将param3(comparand)设置为您知道在变量中看不到的值,如
Int32.MinValue
,然后函数只返回
\u count
的当前值


如果
Interlocked
操作用于变量的所有访问,那么锁是多余的,因为通过
Interlocked
类方法进行的所有访问都是原子的。

我不知道作者为什么选择在类的一部分使用锁,而在其他部分使用无锁技术。但是,我可以假设作者这样做是为了在读取
integer
时创建一个显式的内存障碍。VB不包含与C#的
volatile
关键字等价的内容,因此只剩下4种常用的方法来确保读取安全。我已经按照我为这个特定场景选择的顺序列出了这些

  • 联锁比较交换
  • 螺纹
  • Thread.MemoryBarrier
  • 同步块
内存屏障是防止VB或JIT编译器四处移动指令所必需的。在没有内存屏障的情况下,最有可能的优化是将读取提升到循环外部。考虑这个实际用法:<代码> thcRealth< <代码>属性.< /p>
Sub LoggingThread()
  Do While True
    Trace.WriteLine(ThreadPool.ThreadCount)
  Loop
End Sub
在本例中,CLR可能会内联
ThreadCount
,然后潜在地“提升”对
\u Count
的读取,并在循环开始之前将其缓存在CPU寄存器中。其效果是始终显示相同的值。1


1实际上,
Trace.WriteLine
调用本身会生成一个内存屏障,这会导致代码意外安全。该示例旨在简单说明可能发生的情况。

锁将强制设置内存屏障,因此,如果上次写入的值是由其他CPU写入的,则不会读取CPU缓存中的过时值。使用
Thread.volatireRead()
也可以实现同样的效果,而不需要锁定。

您确定这没有意义吗?添加锁会增加内存障碍,这将阻止指令重新排序,这可能会有所不同。是否阻止对ThreadCount之类的属性进行指令排序?我不这么认为-它将纯粹是一个信息/调试属性。任何真正的逻辑都可以用_Count来完成。@Lasse对
int
的单独读取在.NET中是原子的。只有当调用者同时调用其他成员并且有足够的内联时,重新排序才会出现问题:可能是,但可能意味着紧密耦合,这可能意味着锁定应该在调用者中。可能是,我想指出的是,这个问题可能不像所指出的那样明确。我当然不知道答案。@Richard,重新排序不会有问题,但CPU缓存会有问题。链接中的代码甚至不像线程池。我想最后我会将此页面的链接发送给博客作者:)我想我在学习锁时错过了一些东西。你能解释一下,如果他没有使用Interlocked,而只是在Open/Close中使用锁,为什么锁是必需的吗?@davsan-Interlocked类使用平台特定的处理器指令来保证在访问原始类型的变量(如
Int32
Int64
)或本机指针时的原子行为。如果您可以确保所有对
\u count
的访问都是通过
联锁的
,这将是处理
\u count
上线程安全的最有效方法。任何更高级别的锁都会更昂贵。否则,请摆脱
互锁
用法,并在任何地方使用
锁(\u count)
混合搭配都没有意义。@Steve-好的,我明白你的解释了。我想我错过的是:afaik,lock(CountLock){return\u count;}限制一次只能有一个线程执行{return\u count}部分,那么如果多个线程同时执行同一部分,那么缺点是什么呢?我想我不知道阅读安全问题?@davsan-只要不在其他任何地方使用_count,这可能会起作用。但是,我不确定将联锁操作(在机器级别锁定)与非联锁操作(例如,使用托管代码锁()进行保护)混合使用有多可靠。当另一个线程通过
Interlocked.Decrement
Interlocked.Increment
更新底层内存时,如果您碰巧进入托管代码锁(),我不确定是否保证原子读取。除非您确定,否则我不会混合使用这些数据保护类型。@davsan-另请参阅我关于此主题的问题: