我面临死锁,我的代码结构与此类似:
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
}
}
这很好用。有什么问题?
答案 0 :(得分:4)
问题几乎肯定是你在后台线程中获取锁,然后调用Control.Invoke
,并调用试图获取相同锁的委托(在UI线程上)。它不能这样做,因为另一个线程持有锁 - 并且在等待UI操作完成时将继续保持锁定。
不可否认,您发布的UpdateControl方法中没有锁定,但我怀疑这不是完整的代码 - 而且您没有显示您使用AddItem
或RemoveItem
的位置。
顺便说一下,我注意到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之后,这也运行良好。为什么会这样?