【问题标题】:Problem with events and deadlocks事件和死锁问题
【发布时间】:2013-03-28 23:53:53
【问题描述】:


我在锁内引发事件时遇到问题。
该事件在基类的属性设置器内触发(当我更改属性值时),我在派生类中调用此属性(在锁内)。
代码如下所示:

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 属性在锁外引发事件以保护自己免受死锁,但派生类在自己的锁内设置新状态。 由于派生类的开发人员可能不知道基类是如何工作的,那么确保不会发生死锁的最佳方法是什么?也许在异步线程中引发事件?

【问题讨论】:

  • 为什么要锁定派生类中设置的属性?
  • 我需要锁定更新代码以确保“检查和更新”操作是原子的,否则两个不同的线程可能同时更改属性。如果一个线程调用 getter 而另一个线程调用 setter 来更改状态,也会发生同样的问题,getter 可能不会返回正确的值。

标签: c#


【解决方案1】:

锁定在同一个线程中不会“锁定”,因此我认为您的代码不存在死锁风险。

【讨论】:

  • 是的,但是我们不知道事件触发的用户代码中发生了什么:可能它启动了另一个线程并joins()它,这个线程再次调用了SetStatus()方法,导致僵局
  • @usernnnn:那将是非常糟糕的设计,我完全接受框架应该在客户端搞砸线程时愉快地支持死锁。 [1.] 永远不要在事件处理程序中进行阻塞操作 [2.] 永远不要从多个线程访问服务/UI 元素,除非为此目的明确设计
  • 你是对的,我只是想找到一些方法来 100% 确保不会发生死锁,但我想当你必须“依赖”一些未知的用户代码时这是不可能的..
  • @user728771 嗯,是的,也许问题最终是拥有带锁的属性
【解决方案2】:

好吧,我想我不得不同意那里确实没有陷入僵局的风险。但是,您如何看待使用 BeginInvoke() 启动用户代码?

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

【讨论】:

  • 是的,我也在考虑在异步线程中引发事件并完成它..
【解决方案3】:

当您创建 BaseClass 时,只需将其注释为 ThreadSafe,那么如果任何开发人员实现了此基类并且没有看到它的 cmets 声明它已经是线程安全的,那么这是他们自己的问题。

我认为它们可能是一个属性,表明一个类是线程安全的,但没有。对不起。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多