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

Nik*_* C. 1 c# locking

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

class Foo {
    // ...
    private Dictionary<IAsyncResult, string> fReadRequests;
    private Dictionary<IAsyncResult, string> fWriteRequests;
    private Dictionary<IAsyncResult, string> fSyncRequests;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

ang*_*son 5

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

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

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

只要知道:

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

抵消nbr.2你通常这样做:

private readonly object fLockReadQuests = new object();
Run Code Online (Sandbox Code Playgroud)

然后锁定它.

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