2009-12-11 104 views
2

是否有共同的方式来“共享”在同一组数据上运行的不同对象之间的锁?C#与多线程共享锁

我知道有一个公共对象锁定通常不建议。

例如,队列可以实现为线程安全,但其他一些类可能需要特定的锁才能锁定多个队列操作。如果我有第三个类,那么还需要在这个Queue实例上进行多个锁定操作?

例如: (比方说L<T>是线程安全的名单,只是为了节省一些打字)

class Worker 
{ 
    private readonly L<Something> _list; 
    public Worker(L<Something> list) { _list = list; } 

    private readonly object _lock = new object(); 
    public void Replace(Something old, Something new) 
    { 
     lock (_lock) 
     { 
      if (_list.Contains(old)) 
      { 
       _list.Remove(old); 
       _list.Add(new); 
      } 
     } 
    } 
} 

如果其他类,在不同的线程中,只是在移除old元素if条件下,列表将不再包含该元素,因为_lock是一个私有对象。

我应该锁定实际的列表实例吗?

回答

8

常见的方法是公开一个属性,如ICollection.SyncRoot。当然,大家必须服从锁定才能工作。

如果你可以避免这种情况,并按照ck的建议封装操作,那将会更加健壮和易于理解。

+0

谢谢,这是我的问题的正确答案:共享锁的常用方法。我意识到这些影响,但只是想看看是否有第三种可能性,我不知道。 – Groo 2009-12-11 15:28:13

9

不要将此列表作为属性公开,只能与其交互。然后,您可以处理一个类中的所有锁定,而不处理公共锁定对象。

+0

我明白你的观点,但在这种情况下,所有与这些数据交互的方法必须属于同一个类。你不能有一个不同的类来完成一系列的操作,而且也是线程安全的。 – Groo 2009-12-11 15:08:53

+0

@Robert - 你知道你可以自己编辑帖子,对吧? – Groo 2009-12-11 15:10:10

+0

@Groo re:罗伯特格兰特 - 可以,他是一个当地的傻瓜。 – cjk 2009-12-11 15:17:50

4

从技术上讲,您可以轻松地公开锁定对象。这样做的问题在于,不让他们公开的建议的真正原因是僵局。

如果锁对象被暴露出来,它会带来一些其他代码会锁定在这个对象上而不考虑锁定顺序的风险。这反过来可能导致死锁。

即使锁没有明确暴露,也存在相同的危险。

最好的方法是根本不公开锁 - 既不隐式也不明确。换句话说,将他们完全埋葬在提供服务的班级中。不幸的是,有时这不是一种选择。