我正在使用单声道测试我的应用程序以预置 Linux 端口,但我遇到了线程问题。我最初考虑在这里粘贴 3000 行代码,但最后我设计了一个小的最小示例;)
您有一个带有按钮的表单(诗意地命名为Button1
,和一个标签(毫无疑问,它带有名称Label1
))。整个过程就是在一种叫做Form1
. 单击Button1
会启动一个无限循环,该循环会增加本地计数器并更新Label1
(使用Invoke
)以反映其值。
现在在 Mono 中,如果您调整表单大小,标签将停止更新,永远不会重新启动。MS 实现不会发生这种情况。BeginInvoke
没有更好的工作;更糟糕的是,它会使 UI 在这两种情况下都挂起。
你知道这种差异是从哪里来的吗?你会怎么解决?最后,为什么 BeginInvoke 在这里不起作用?我一定是犯了一个大错……但是哪个?
编辑:到目前为止的一些进展:
- 调用 BeginInvoke 确实有效;只是,用户界面的刷新速度不够快,所以它似乎停止了。
- 在单声道上,当您在 UI 队列中插入消息(例如,通过调整表单大小)时,整个线程会挂起。事实上,同步
Invoke
调用永远不会返回。我试图理解为什么。 - 有趣的是:即使使用
BeginInvoke
,在调整大小操作结束之前也不会执行异步调用。在 MS.Net 上,它们在调整大小的同时继续运行。
代码如下所示(C# 版本较低):
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim T As New Threading.Thread(AddressOf Increment)
T.Start()
End Sub
Sub UpdateLabel(ByVal Text As String)
Label1.Text = Text
End Sub
Delegate Sub UpdateLabelHandler(ByVal Text As String)
Sub Increment()
Dim i As Long = 0
Dim UpdateLabelDelegate As New UpdateLabelHandler(AddressOf UpdateLabel)
Try
While True
i = (i + 1) Mod (Long.MaxValue - 1)
Me.Invoke(UpdateLabelDelegate, New Object() {i.ToString})
End While
Catch Ex As ObjectDisposedException
End Try
End Sub
End Class
或者,在 C# 中,
public class Form1
{
private void Button1_Click(System.Object sender, System.EventArgs e)
{
System.Threading.Thread T = new System.Threading.Thread(Increment);
T.Start();
}
public void UpdateLabel(string Text)
{
Label1.Text = Text;
}
public delegate void UpdateLabelHandler(string Text);
public void Increment()
{
long i = 0;
UpdateLabelHandler UpdateLabelDelegate = new UpdateLabelHandler(UpdateLabel);
try {
while (true) {
i = (i + 1) % (long.MaxValue - 1);
this.Invoke(UpdateLabelDelegate, new object[] { i.ToString() });
}
} catch (ObjectDisposedException Ex) {
}
}
}