死锁的lock()方法

时间:2009-02-17 12:40:15

标签: c# locking deadlock

我面临死锁,我的代码结构与此类似:

private delegate void UpdateControlDelegate(string value);

public void UpdateControl(string value)
{
    if (txtAddress.InvokeRequired)
    {
        txtAddress.Invoke(new UpdateControlDelegate(UpdateControl), value);
    }
    else
    {
        txtAddress.Text = value; // This is in GroupBox1
        txtValue.Text = value; // This is in GroupBox2
    }
}

class ThreadHandler
{
    List<string> _list = new List<string>();
    object _criticalSection = new object();

    public ThreadHandler()
    {
        new Thread(new ThreadStart(Run)).Start();
    }

    public static ThreadHandler _threadHandler = null;

    public static ThreadHandler GetThreadHandler()
    {
        if (_threadHandler == null)
        {
            _threadHandler = new ThreadHandler();
        }

        return _threadHandler;
    }

    public void Run()
    {
        while (true)
        {
            // some code

            lock (_criticalSection)
            {
                foreach (string str in _list)
                {
                    // some Code
                }
            }

            // some code
            Thread.Sleep(SomeTime);
        }
    }

    public void AddItem(string item)
    {
        lock (_criticalSection)
        {
            _list.Add(item);
        }
    }

    public void RemoveItem(string item)
    {
        lock (_criticalSection)
        {
            _list.Remove(item);
        }
    }

}

但是使用相同的代码,我只是像这样修改了UpdateControl方法:

private delegate void UpdateControlDelegate(string value);

public void UpdateControl(string value)
{
    if (InvokeRequired)
    {
        BeginInvoke(new UpdateControlDelegate(UpdateControl), value);
    }
    else
    {
        txtAddress.Text = value; // This is in GroupBox1
        txtValue.Text = value; // This is in GroupBox2
    }
}

这很好用。有什么问题?

3 个答案:

答案 0 :(得分:4)

问题几乎肯定是你在后台线程中获取锁,然后调用Control.Invoke,并调用试图获取相同锁的委托(在UI线程上)。它不能这样做,因为另一个线程持有锁 - 并且在等待UI操作完成时将继续保持锁定。

不可否认,您发布的UpdateControl方法中没有锁定,但我怀疑这不是完整的代码 - 而且您没有显示您使用AddItemRemoveItem的位置。

顺便说一下,我注意到GetThreadHandler()不是线程安全的 - 这看起来像是一个bug ...

答案 1 :(得分:0)

从工作线程调用UpdateControl时,是否从主线程调用AddItem和RemoveItem?这将导致死锁。

答案 2 :(得分:0)

这是我的代码,

public class ValueReader
{
    List<IDataReader> _list = new List<IDataReader>();

    object _criticalSection = new object();

      public ValueReader()
      {
        //Nothign here
      }

      public void Attach(IDataReader reader)
      {
            lock(_criticalSection)
            {
                _list.Add(reader);
            }
      }

      public void Detach(IDataReader reader)
      {
            lock(_criticalSection)
            {
                _list.Remove(reader);
            }
      }

      public void Notify(string value)
      {
            lock(_criticalSection)
            {
                foreach(IDataReader reader in _list)
                {
                    reader.Update(value);
                }
            }
        }

      public void Start()
      {
            new Thread(new ThreadStart(Run)).Start();
      }


      private void Run()
      {
            while(true)
            {

                //generate value
                Notify(value);

                Thread.Sleep(5000);

            }
      } 

}




public interface IDataReader
{
    void UpdateControls(string value);
}

public class FirstClass : IDataReader
{

    ....
    ......  
    ValueReader _reader = null;

    public FirstClass()
    {

        _reader = new ValueReader();
              _reader.Start();
        _reader.Attach(this);

    }

    private void AddToSmartClient()
    {
        // _reader has added to SmartClient's WorkItem
    }


    private delegate void UpdateControlDelegate(string value);

    public void UpdateControl(string value)
    {
        if(txtAddress.InvokeRequired)
        {
            txtAddress.Invoke(new UpdateControlDelegate(UpdateControl), value);
        }
        else
        {
            txtAddress.Text = value;
            txtValue.Text = value;
        }
    }

}


public class SecondClass : IDataReader
{
        ....
    ......
    ValueReader _reader = null;

    public void SecondClass()
    {
        _reader = ReadFromSmartClient();
        _reader.Attach(this);
    }

    private ValueReader ReadFromSmartClient()
    {
        reader = //Get from SmartClient's Workitem.
        return reader
    }

    private delegate void UpdateControlDelegate(string value);

    public void UpdateControl(string value)
    {
        if(InvokeRequired)
        {
            BeginInvoke(new UpdateControlDelegate(UpdateControl), value);
        }
        else
        {
            control1.Text = value;
            control2.Text = value;
        }
    }

}

我只调用了FirstClass一段时间。在这种情况下,它的工作正常。经过一段时间后我调用了Second类,此时从secondClass调用Attach时,应用程序挂起了。(我monitered它直到Attach方法的锁定(_criticalSection)。

经过一段时间后,我将Frist Class中的Update控件转换为

     public void UpdateControl(string value)
{
    if(InvokeRequired)
    {
        BeginInvoke(new UpdateControlDelegate(UpdateControl), value);
    }
    else
    {
        txtAddress.Text = value;
        txtValue.Text = value;
    }
}

在调用SecondClass之后,这也运行良好。为什么会这样?