【问题标题】:Why use System.Threading.Interlocked.Decrement instead of minus?为什么使用 System.Threading.Interlocked.Decrement 而不是减号?
【发布时间】:2009-12-01 20:33:28
【问题描述】:

我将一些 c# 代码转换为 vb.net,converter.telerik.com 变成了这个:

i--;

进入这个:

System.Math.Max(System.Threading.Interlocked.Decrement(i), i + 1)

所有的花哨是怎么回事?

【问题讨论】:

  • 它对局部变量执行此操作,并且不使用 Math.Max() 的返回值。那是一个糟糕的转换器。

标签: c# vb.net c#-to-vb.net


【解决方案1】:

Michał Piaskowski 的评论引发了以下解释:

C#中i--的语义是返回i的当前值(即减量前的值),然后将i减一。

因此,我们需要将其转换为 VB。我们不能使用i -= 1,因为这不会返回递减前i 的当前值。所以,我们需要一个操作来递减i,但在递减之前返回i 的值,类似于:

Function DoPostDecrement(ByRef i As Integer) As Integer
    i -= 1
    Return i + 1
End Function

但这建议使用以下内容来避免必须编写方法来执行上述操作:

System.Math.Max(
    someValueThatIsEqualToiMinusOne,
    someValueThatIsEqualtoiBeforeTheDecrement
)

但是 VB.NET 不允许您使用 i -= 1i = i - 1 代替 someValueThatIsEqualToiMinusOne。但是,System.Threading.Interlocked.Decrement(i) 是合法的,并且等于 i - 1 的值。一旦你这样做了,因为参数是从左到右评估的,someValueThatIsEqualtoiBeforeTheDecrement 应该是i + 1(此时已经执行减量到i + 1 是预减量值。

请注意,上述方法DoPostDecrementSystem.Math.Max, System.Threading.Interlocked.Decrement 构造在多线程上下文中可能具有不同的语义。

【讨论】:

  • i = i - 1;与 i-- 不一样;它是 --i;
【解决方案2】:

联锁操作为atomic;如果你小心的话,在多线程上下文中,你可以安全地使用它而无需持有锁。

【讨论】:

  • 是的,但我认为这不是它被使用的原因。它只是用作在 VB.Net 中转换运算符的便捷方式。 C# --- 运算符不是原子的:而且我认为翻译后的代码片段也不是原子的(如果另一个线程在减量和计算 i+1 之间修改 i 怎么办)?
【解决方案3】:

我能看到的唯一原因是来自

Interlocked.Decrement Method

递减一个指定的变量并且 将结果存储为原子 操作。

【讨论】:

    【解决方案4】:

    这取决于 - “i”是共享变量吗?是否在线程安全的环境中?

    如果“i”是一个整数,那么 i-- 基本上会执行以下操作(忽略细节):

    1. i 减一
    2. 将该值分配回 i

    如您所见,有 > 1 个步骤。如果“i”位于非线程安全的位置(跨线程共享的静态变量等),那么线程可能会在这两个步骤的中间停止,另一个线程可以运行这两个步骤,然后你就会有无效数据的问题。

    Interlocked 类本质上将上述两个步骤组合成一个步骤,提供原子操作。现在您不必担心线程,因为它是单个操作,不能被另一个线程中断。

    【讨论】:

    • 在另一条评论中:“我认为它不应该因为它可以改变多线程上下文中的语义。”在单线程上下文中,行为不变。在多线程上下文中,行为现在可以保证做一些可预测的事情,这是以前不会的。所以无论哪种方式,这都是一个“好的改变”。
    • 是的,但我认为这不是使用增量的原因。它只是用作在 VB.Net 中转换运算符的便捷方式。 C# -- 运算符不是原子的:而且我认为翻译后的代码片段也不是原子的 - 如果另一个线程在减量和评估 i+1 之间修改 i 怎么办? msdn.microsoft.com/en-us/library/aa446528.aspx
    • 好点马克...不知何故我对 i+1 在那里的事实感到震惊:) 我相信你是对的,它只是一个转换的东西。
    【解决方案5】:

    要回答您的问题,看起来converter.telerik.com 对线程问题过于保守了。 WAAAY 过于保守。如果i 的同一个实例没有从多个线程同时发生变异,我会将代码恢复为i--

    【讨论】:

    • 我认为 Decrement 只是被用作将 -- 运算符转换为 VB.Net 的便捷方式。 VB.Net 中没有 -- 运算符,因此您不能将代码“还原”为 i--,除非您将其还原为 C#
    • 啊,我明白了。感谢您澄清这一点!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2013-12-28
    • 2014-10-12
    相关资源
    最近更新 更多