Skip to main content
 首页 » 编程设计

c#之我可以锁定类实例变量的副本吗

2024年02月01日31三少

在 C# 中,类实例是引用类型。这是否意味着可以锁定 new 返回值的副本?就我而言,我有一个包含一些需要锁定的字段的类:

class Foo { 
    // ... 
    private Dictionary<IAsyncResult, string> fReadRequests; 
    private Dictionary<IAsyncResult, string> fWriteRequests; 
    private Dictionary<IAsyncResult, string> fSyncRequests; 
} 

在特定方法中,我需要对所有这些字段执行相同的操作。因此,为了避免代码重复,我通过将字段复制到数组中来循环执行操作:

var dictArray = new[] { fReadRequests, fWriteRequests, fSyncRequests }; 
foreach (var reqDict in dictArray) { 
    lock (reqDict) { 
        foreach (var i in reqDict) { 
            // Do something with the request. 
        } 
    } 
} 

这样安全吗?即使应用锁的变量是原始变量的副本,锁定也能按预期工作吗?

请您参考如下方法:

是的,您永远不会锁定保存引用的变量,您总是锁定实例。

在您的情况下,您复制的是引用,而不是对象,因此您在这些字段中处理的是相同的对象。

锁定那些应该工作得很好。

只知道:

  1. 锁定对象不会以任何方式阻止其他线程访问同一对象。如果其他线程没有锁定,它会跳华尔兹并更改对象,而不会理会您的锁定。
  2. 不要锁定您不拥有的对象,以及您发布给他人的对象。您需要确保您的代码是唯一锁定该对象的代码,否则如果其他一些代码也持有该对象的锁,您仔细的同步代码可能会突然停止。
  3. 永远不要锁定值类型,即使您将它们放在 object 变量中也是如此。每次将值类型复制到 object 变量中时,您都会得到一个新副本,它将有自己的锁。

为了抵消 nbr。 2 你通常这样做:

private readonly object fLockReadQuests = new object(); 

然后锁定它。

但同样,您在问题中的假设成立。