代码之家  ›  专栏  ›  技术社区  ›  We Are All Monica

传递给其他线程的对象上的锁会发生什么情况?

  •  1
  • We Are All Monica  · 技术社区  · 15 年前

    我不太确定该怎么说,所以我只需粘贴我的代码并问问题:

    private void remoteAction_JobStatusUpdated(JobStatus status) {
        lock (status) {
            status.LastUpdatedTime = DateTime.Now;
            doForEachClient(c => c.OnJobStatusUpdated(status));
            OnJobStatusUpdated(status);
        }
    }
    
    private void doForEachClient(Action<IRemoteClient> task) {
        lock (clients) {
            foreach (KeyValuePair<RemoteClientId, IRemoteClient> entry in clients) {
                IRemoteClient clientProxy = entry.Value;
                RemoteClientId clientId = entry.Key;
                ThreadPool.QueueUserWorkItem(delegate {
                    try {
                        task(clientProxy);
    #pragma warning disable 168
                    } catch (CommunicationException ex) {
    #pragma warning restore 168
                        RemoveClient(clientId);
                    }
                });
            }
        }
    }
    

    假设修改 status 对象将首先获取它的锁。

    自从 地位 对象一直传递到多个 ThreadPool 线程,以及对 ThreadPool.QueueUserWorkItem 将在实际任务完成之前完成,我是否确保相同 地位 对象被发送到所有客户端?

    换一种说法,什么时候 lock (status) 语句“expire”或导致其锁被释放?

    2 回复  |  直到 15 年前
        1
  •  5
  •   Martin Liversage    15 年前

    锁没有 到期 . 当线程试图通过 lock 语句它只能在没有其他线程在 对在中使用的特定对象实例具有锁的块 状态。

    在您的例子中,似乎有一个主线程正在执行。它会锁定两个 status 以及 clients 在它旋转在单独线程上执行的新任务之前的实例。如果新线程中的任何代码希望在 地位 客户 它必须等待,直到主线程释放了两个锁 阻碍。当 remoteAction_JobStatusUpdated 返回。

    你通过了 地位 对象到每个工作线程,它们都可以自由地对该对象做任何他们想做的事情。声明 lock (status) 绝不能保护 地位 实例。但是,如果任何线程尝试执行 锁定(状态) 它们将阻塞,直到主线程释放锁为止。

    使用两个单独的对象实例锁定可能导致死锁。假设一个线程执行以下代码:

    lock (status) {
      ...
      lock (clients) {
        ...
      }
    

    }

    另一个线程在按相反顺序获取锁的位置执行以下代码:

    lock (clients) {
      ...
      lock (status) {
        ...
      }
    

    }

    如果第一个线程设法首先获得状态,而第二个线程首先锁定客户机,则它们将死锁,两个线程将不再运行。

    一般来说,我建议您将共享状态封装到一个单独的类中,并使对它的访问线程安全:

    class State {
    
      readonly Object locker = new Object();
    
      public void ModifyState() {
        lock (this.locker) {
          ...
        }
      }
    
      public String AccessState() {
        lock (this.locker) {
          ...
          return ...
        }
      }
    
    }
    

    您还可以使用标记方法 [MethodImpl(MethodImpl.Synchronized)] 属性,但它有其缺陷,因为它将用 lock (this) 一般不建议这样做。

    如果你想更好地了解 陈述你可以读 Safe Thread Synchronization 在msdn杂志上的文章。

        2
  •  0
  •   Grzenio    15 年前

    锁当然不会自行“过期”,锁在lock(..)语句的右大括号之前是有效的。