我在C#中的处理线程遇到问题。基本上,线程在新消息到达或发送时管理聊天窗口,不幸的是,我根据运行环境出现了不同的情况。Application.Run()在不包含调试器的版本构建中运行方式不同于调试版本
当运行Debug版本(无论是否带有调试器)或Release版本在调试器下时,Process()函数正确运行,显示窗口并收到正确的消息。
然而,当运行一个没有调试器的Release版本时,Application.Run()调用似乎停止处理主进程()线程(注意这个调用发生在处理线程的一个子线程下)因此不再发生处理。
通过使用MessageBox.Show()调用我已经确定Application.Run()是最后一次调用之前没有更多的消息框显示(他们应该是因为它显示了多少消息是每次while循环运行时收到)。
有没有人知道为什么Application.Run()调用在这种情况下表现不同?
/// <summary>
/// Processes the IM message queue, managing the chat windows and messages.
/// </summary>
private void Process()
{
try
{
MessageBox.Show("MessageQueue process has started!");
while (this.m_Running)
{
List<Message> messages = null;
lock (this.m_Lock)
{
messages = new List<Message>(this.m_Messages);
MessageBox.Show("MessageQueue received " + this.m_Messages.Count + " messages on this spin.");
this.m_Messages.Clear();
}
// Process all the messages
foreach (Message m in messages)
{
Contact c = m.Contact;
if (!this.m_Windows.Keys.Contains(c.ID) || this.m_Windows[c.ID] == null)
{
MessageBox.Show("MessageQueue is creating a new window.");
bool complete = false;
Thread t = new Thread(() =>
{
try
{
ChatWindow w = new ChatWindow(this, c, new Contact(this.m_Client.JID, null));
w.Load += (sender, e) =>
{
if (m.IsTo)
w.AppendSentMessage(m.To, m.Data);
else if (m.IsFrom)
w.AppendRecievedMessage(m.From, m.Data);
w.UpdateStatus(c);
};
w.FormClosed += (sender, e) =>
{
this.m_Windows[c.ID] = null;
};
c.StatusUpdated += (sender, e) =>
{
RoketPack.Manager.VoidLambda lambda =() =>
{
w.UpdateStatus(c);
};
if (w.InvokeRequired)
w.Invoke(lambda);
else
lambda();
};
MessageBox.Show("MessageQueue is now showing the new window.");
w.Show();
if (!this.m_Windows.Keys.Contains(c.ID))
this.m_Windows.Add(c.ID, w);
else
this.m_Windows[c.ID] = w;
complete = true;
MessageBox.Show("MessageQueue is now running the new window.");
Application.Run(w);
MessageBox.Show("MessageQueue is now closing the window.");
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
complete = true;
}
});
t.Name = "IM Chat Window - " + c.ID;
t.IsBackground = true;
t.Start();
// We have to wait until the form has been added to the dictionary.
while (!complete) ;
}
else
{
RoketPack.Manager.VoidLambda lambda =() =>
{
if (m.IsTo)
this.m_Windows[c.ID].AppendSentMessage(m.To, m.Data);
else if (m.IsFrom)
this.m_Windows[c.ID].AppendRecievedMessage(m.From, m.Data);
MessageBox.Show("MessageQueue appended the message to the chat window.");
};
MessageBox.Show("MessageQueue received a message and is now forwarding it onto the chat window.");
if (this.m_Windows[c.ID].InvokeRequired)
this.m_Windows[c.ID].Invoke(lambda);
else
lambda();
}
}
// Sleep for 10 milliseconds.
Thread.Sleep(10);
}
}
finally
{
MessageBox.Show("MessageQueue process has terminated!");
}
}
是的,这可能不是最佳的,但它也不是问题的原因,因为消息框在complete设置为true后显示(所以while循环会中断)。 – 2010-11-08 07:49:56
我改变了代码,使用Wait/Notify方法和w.ShowDialog()来代替,它似乎解决了这个问题。我相信这是CLR优化的问题,如http://www.albahari.com/threading/part4.aspx#_Memory_Barriers_and_Volatility中所述,可能会导致诸如完整布尔值在添加字典值之前设置为true的问题(这当然会导致线程崩溃)。添加Wait/Notify方法隐式地通过所需的锁定语句给出了内存屏障。 – 2010-11-08 10:21:53
@Hach - 与内存屏障无关,这是应该使用* volatile *关键字的地方。但是,不要,ARE是优越的。 – 2010-11-08 10:33:22