2011-04-28 92 views
1


我有养育锁内的事件的一个问题。
事件是在基类中的属性setter中触发的(当我更改属性值时),并且我在派生类(在锁内)中调用此属性。
代码看起来是这样的:问题的事件和死锁

class BaseClass 
{ 
    public event EventHandler StatusChanged; 

    int _status = 0; 
    object lockA = new object(); 

    public int Status 
    { 
     get 
     { 
      lock (lockA) { return _status; } 
     } 
     set 
     { 
      bool fireEvent = false; 
      lock (lockA) 
      { 
       if (_status != value) 
       { 
        _status = value; 
        fireEvent = true; 
       } 
      } 

      if (fireEvent) 
       StatusChanged(this, EventArgs.Empty); 
     } 
    } 
} 

class DerivedClass : BaseClass 
{ 
    object lockB = new object(); 

    public void SetStatus(int newStatus) 
    { 
     lock (lockB) 
     { 
      this.Status = newStatus; 
     } 
    } 
} 

的BaseClass的特性提高了锁外活动,以保护自己免受死锁,但派生类中设置自己的锁内的新状态。 由于派生类的开发人员可能不知道基类是如何工作的,确保死锁不会发生的最好方法是什么?也许在异步线程中引发事件?

+1

你为什么要锁定派生类中的属性集? – 2011-04-28 07:44:43

+0

我需要锁定更新代码以确保“检查和更新”操作是原子操作,否则两个不同的线程可能会同时更改属性。如果一个线程调用getter而第二个线程调用setter来更改状态,则同样的问题会发生,getter可能不会返回正确的值。 – Francesco 2011-04-28 07:49:42

回答

0

嗯,我想我必须同意,那里确实没有死锁的风险。但是,您如何看待使用BeginInvoke()来启动用户代码?

BeginInvoke(this, EventArgs.Empty, null, null); 
+0

是的,我也在考虑在异步线程中提高事件的性能。 – Francesco 2011-04-28 08:01:41

1

锁在同一个线程不“锁定”,所以在我和你的代码意见不被死锁风险。

+0

是的,但我们不知道事件触发的用户代码会发生什么情况:也许它会启动另一个线程并加入( )它,并且此线程再次调用SetStatus()方法,导致死锁 – Francesco 2011-04-28 07:51:38

+0

那么,你不能这样做。 – 2011-04-28 07:52:39

+0

@usernnnn:这将是特别糟糕的设计,我完全同意,当客户端弄乱线程时,框架应该愉快地支持死锁。 [1.]永远不要在事件处理程序中执行阻塞操作[2.]永远不要从多个线程访问服务/ UI元素,除非明确地设计用于此目的 – sehe 2011-04-28 07:56:20

0

当您创建BaseClass的只是评论它作为是线程安全的,那么如果任何开发人员实现这个基类,并没有看到它的评论状态,这已经是线程安全的,然后它自己的问题。

我以为他们可能是一个属性,指出一个类是线程安全的,但没有一个。抱歉。