C#中的锁定范围:返回的对象是否仍然“锁定”?

时间:2012-04-01 17:55:19

标签: c# multithreading thread-safety

假设我有一个包含

的对象A.
// ...

private List<double> someList = new List<double>();

// ... 

public List<double> SomeList
{
    get { lock (this) { return someList; } }
}

// ...

在列表中执行操作是否是线程安全的,如下面的代码所示。知道几个操作可以由不同的线程同时执行。

A.SomeList.Add(2.0);

A.SomeList.RemoveAt(0);

换句话说,什么时候释放锁?

6 个答案:

答案 0 :(得分:12)

这里没有线程安全。

lock一旦其保护的块完成,就会在属性返回之前立即释放,因此对Add ad RemoveAt的调用不受锁的保护。< / p>

答案 1 :(得分:5)

你在问题​​中显示的锁定用处不大。

要使列表操作线程安全,您需要实现自己的Add / Remove / etc方法,包装列表中的那些。

public void Add(double item)
{
    lock(_list)
    {
        _list.Add(item);
    }
}

此外,最好将列表本身隐藏在班级的消费者中,即将字段设为私有。

答案 2 :(得分:3)

退出lock语句的正文时会释放锁定。这意味着您的代码线程安全。

换句话说,您可以确保两个线程不会同时在同一个对象上执行return someList。但是,当一个线程同时执行Add()并且另一个线程将执行RemoveAt()时,肯定有可能执行{{1}},这使得它不是线程安全的。

答案 3 :(得分:2)

当锁内部的代码执行完毕后,锁被释放。 此外,对此进行锁定只会影响对象的当前实例

答案 4 :(得分:1)

好的,只是为了它的地狱 通过使用已经线程安全的体系结构,有一种方法可以使对象线程安全。

例如,您可以将对象设置为单个线程 COM 对象。 COM对象将是线程安全的,但您将支付性能(懒惰的价格而不是管理自己的锁)。

<强> Create a COM Object in C#

答案 5 :(得分:0)

......其他人已经说过,但只是为了使问题正式化......

  • 首先,lock (this) {...}表示“范围” - 例如像using (){} - 它只锁定(在本例中为)变量里面的变量。这实际上是一件“好事”:),好像你不能依赖它,整个锁/同步概念将毫无用处,
  • lock (this) { return something; }是一种矛盾的东西 - 它会返回一些东西,在它返回的同一时刻解锁,
  • 我认为问题在于理解它是如何运作的。 'lock()'在对象状态下没有'持久',因此你可以返回等等。看看它是如何实现的How does lock work exactly? - 答案解释了它。它更像是一个“关键部分” - 即你保护'代码'的某些部分,它使用变量 - 而不是变量本身。任何类型的同步都需要“同步对象”来保存锁定 - 并且一旦不再需要锁定就被处理掉。看一下这篇文章https://stackoverflow.com/a/251668/417747,Esteban很好地阐述了这个帖子,
  

“最后,有一种常见的误解,即lock(this)实际上修改了作为参数传递的对象,并以某种方式使其成为只读或不可访问。这是错误的。该对象作为参数传递锁定只是作为一个关键“(这是一个引用)

  • 你要么(通常)锁定类方法,属性的'私有代码'... - 同步对你正在做的事情的访问 - 并且访问私有成员(通常也是这样),这样其他任何人都不能无需通过同步代码即可访问它。
  • 或者你创建一个线程安全的“结构” - 就像一个列表 - 它已经在内部“同步”,以便你可以以线程安全的方式访问它。但是没有这样的东西(或者没有使用,几乎从不),因为传递锁定或者有一个地方锁定变量,而代码的另一部分解锁它等等(在这种情况下,它是某种类型的EventWaitHandle相当用于同步“远程”代码之间的事物,而另一个代码则触发另一个等等。)
  • 在您的情况下,我认为选择'同步结构',即内部处理的列表,