我可以锁定类实例变量的副本吗?

时间:2014-01-11 12:15:08

标签: c# locking

在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 个答案:

答案 0 :(得分:5)

是的,你永远不会锁定包含引用的变量,你总是锁定实例

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

锁定那些应该可以正常工作。

只知道:

  1. 锁定对象不会以任何方式阻止其他线程访问同一对象。如果其他线程没有锁定,它将直接跳入并更改对象锁定的锁定。
  2. 不要锁定您不拥有的对象以及您向其他人发布的对象。您需要确保您的代码是唯一一个锁定该对象的代码,否则如果某些其他代码也锁定它,您的仔细同步代码可能会突然停止。
  3. 永远不要锁定值类型,即使它们在object变量中也有。每次将值类型复制到object变量中时,您都会获得一个新副本,它将拥有自己的锁。
  4. 抵消nbr。 2你通常这样做:

    private readonly object fLockReadQuests = new object();
    

    然后锁定它。

    但同样,你在问题中的假设仍然存在。