【问题标题】:Can I lock(something) on one line in C#?我可以在 C# 中的一行上锁定(某物)吗?
【发布时间】:2009-08-14 06:55:44
【问题描述】:

下面的 _otherThing 字段会被锁保护吗?

class ThreadSafeThing
{
    private readonly object _sync = new object();

    private SomeOtherThing _otherThing;

    public SomeOtherThing OtherThing { get { lock(_sync) return _otherThing; } }

    public void UpdateOtherThing(SomeOtherThing otherThing)
    {
        lock(_sync) _otherThing = otherThing;
    }
}

【问题讨论】:

    标签: c# multithreading syntax locking


    【解决方案1】:

    是的。

    这与锁无关。 C# 程序使用语句来表达。使用 {} 将多个语句分组为一个块。块可以在允许单个语句的上下文中使用。请参阅 C# 语言规范第 1.5 节。

    【讨论】:

    • 感谢您解释答案。
    • 类、函数、枚举等定义需要块。尝试、捕获并最终需要块。所以块和语句并不是完全可以互换的。
    • @ChadSchouggins 我没有说他们是。我说过一个块可以用在允许single statement的地方,这是语言规范的规定。
    【解决方案2】:

    这个结构:

    lock(_sync) _otherThing = otherThing;
    

    ...与此构造相同:

    lock(_sync)
    {
        _otherThing = otherThing;
    }
    

    所以是的,_otherThing 的分配受锁保护。

    【讨论】:

      【解决方案3】:

      是的,它将受到保护,因为 _sync 对象不会改变。

      编辑:您在此处使用的锁几乎肯定不是您的意思,如本线程的其他几个答案中所述。

      【讨论】:

      • @280Z28:如果 SomeOtherThing 是 struct,则分配可能不是原子的。
      • 谢谢。我的例子很简单,只是为了方便提问。
      • @Fredrik:我不敢相信我让那个人溜走了。 doublelong 在 32 位机器上也是如此。
      【解决方案4】:

      据我所知

      lock(_sync)
        _otherThing = otherThing;
      

      一样
      lock(_sync) _otherThing = otherThing;
      

      一样
      lock(_sync)
      {
        _otherThing = otherThing;
      }
      

      类似于

      if(something)
        _otherThing = otherThing;
      

      相同
      if(something)
      {
        _otherThing = otherThing;
      }
      

      (我所说的相似是指语法上的相似,而不是功能上的相似。iflock 当然不同:p)

      实际上你可以使用{ },即使没有lockif或任何类似于组语句的东西。

      【讨论】:

        【解决方案5】:

        您的代码不是线程安全的,因为您处理引用。

        除非您的锁唯一阻止的是返回对您的对象的引用(这是没有锁的线程安全,请参阅 C# 语言规范的第 5.5 节),否则您将不会更改 _otherThing 线程安全。

        在这种情况下,您需要使您的 mutators 和 accessors 线程安全(通过锁定对象的更改和读取)。

        【讨论】:

        • 谢谢。 SomeOtherThing 也可以是值类型,但我不是在问如何锁定事物,而是在问语法。
        • SomeOtherThing 也可以是不可变的。不过,就内存模型而言,锁确实还有其他用途。
        • 想详细说明那个乔恩?如果您的类型是不可变的,我会遵循,那么是的,您可以给出引用而不必担心。你指的是什么记忆模型效应?如果您正在处理引用类型以及 5.5 中描述的许多值类型,那么您有线程安全分配和读取,锁只会减慢您的速度。
        • @Spence:分配是原子的,但不是线程安全的 - 除非您将“无法保证读取线程将看到另一个线程写入的新值”作为线程安全。您需要该字段是易失性的,或者具有其他内存屏障(包括锁)。
        • 啊,你当然指的是缓存值。因此,您需要内存屏障或锁定以将该引用从缓存中刷新到所有处理器上的主内存。并发编程很有趣……顺便说一句,为您的回复干杯。
        【解决方案6】:

        这会奏效。单语句和块语句在 C# 语法中几乎总是可以互换的(方法体等除外)。

        但是,甚至可能根本不需要进行锁定。如果您想防止在进行其他更改时更改属性,那么可以。如果SomeOtherThing 是值类型(struct),您还需要锁定它。

        如果您选择不使用锁,则需要声明字段volatile,以确保您的更改立即在其他线程中可见。

        【讨论】:

        • 或者,如果您想确保其他线程可以看到您的更改...通常在读取或更新共享内存时需要一些类型的内存屏障,以确保适当的可见性。
        • volatile 应该这样做。我想添加它,但 iPhone 3.0 软件上的 Safari 真的不喜欢 Stack Overflow。你去吧:P
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-25
        • 1970-01-01
        • 2019-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多