0

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

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
    }
}

这工作正常。问题是什么?

4

3 回答 3

4

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

诚然,您发布的 UpdateControl 方法中没有锁定,但我怀疑这不是完整的代码 - 而且您没有显示您正在使用的位置AddItemRemoveItem.

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

于 2009-02-17T12:43:41.507 回答
0

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

于 2009-02-17T12:47:19.330 回答
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 时,应用程序挂起。(我监测到它正在运行,直到 Attach 方法的锁(_criticalSection)。

一段时间后,我将第一类中的更新控件转换如下

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

这在调用 SecondClass 之后也很有效。为什么会发生?

于 2009-02-17T14:07:19.827 回答