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

本文关键字:锁定 对象 范围 返回 | 更新日期: 2023-09-27 18:29:37

假设我有一个对象 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);

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

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

这里没有线程安全。

lock在它保护的块完成后立即释放,就在属性返回之前,因此对Add广告RemoveAt的调用不受锁的保护。

您在问题中显示的锁没有多大用处。

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

public void Add(double item)
{
    lock(_list)
    {
        _list.Add(item);
    }
}
此外,最好

对类的使用者隐藏列表本身,即将字段设为私有。

当您退出 lock 语句的正文时,锁将释放。这意味着您的代码不是线程安全的。

换句话说,您可以确定两个线程不会同时对同一对象执行return someList。但是当然有可能一个线程将同时执行Add()而另一个线程将执行RemoveAt(),这就是它非线程安全的原因。

当锁中的代码完成执行时,锁被释放。此外,锁定此内容只会影响对象的当前实例

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

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

在 C# 中创建 COM 对象

...其他人已经说过了,但只是为了稍微正式化一个问题......

  • 首先,lock (this) {...}建议使用"作用域"(例如,像using (){}一样(,它只锁定(在本例中为(内部变量。这是一件"好事":)实际上,好像你不能依赖整个锁/同步概念将非常无用,
  • lock (this) { return something; }是某种矛盾的 - 它返回的东西在它返回的同一刻解锁,
  • 我认为问题在于对它如何工作的理解。'lock((' 不会在对象的某个状态中"持久化",因此您可以返回它等。看看它是如何实现的 锁究竟是如何工作的?- 答案解释它。它更像是一个"关键部分" - 即你保护使用变量的"代码"的某些部分 - 而不是变量本身。任何类型的同步都需要"同步对象"来保存锁 - 并且在不再需要锁时将其处理。看看这篇文章 https://stackoverflow.com/a/251668/417747,埃斯特万制定得很好,

"最后,有一个常见的误解,即 lock(this( 实际上修改了作为参数传递的对象,并以某种方式使其只读或无法访问。这是错误的。作为参数传递到锁定的对象仅用作密钥">(这是引用(

  • 您要么(通常(锁定类方法的"私有代码",属性... - 同步访问您正在内部执行的操作 - 并访问私有成员(通常再次(,以便没有其他人可以访问它而无需通过您的同步代码。
  • 或者你创建一个线程安全的"结构"——比如一个列表——它已经在里面"同步"了,以便你可以以线程安全的方式访问它。但是没有这样的事情(或者不使用,几乎从不(传递锁或让一个地方锁定变量,而代码的另一部分解锁它等(在这种情况下,它是某种类型的EventWaitHandle,而是用于同步"远程"代码之间的事物,其中一个在另一个代码上触发等。
  • 在您的情况下,我认为选择"同步结构",即内部处理的列表,