Linuxポートを想定してアプリをmonoでテストしていますが、スレッドに問題があります。最初はここに3000コード行を貼り付けることを検討しましたが、最後に小さな最小限の例を考案しました;)
ボタン付きのフォームがあります(詩的に名前が付けられButton1
、ラベル(当然のことながら名前が付けられていますLabel1
))。たくさんの人がと呼ばれる形で幸せな生活を送っていForm1
ます。クリックするButton1
と、ローカルカウンターをインクリメントし、その値を反映するようにLabel1
(を使用して)更新する無限ループが起動します。Invoke
現在Monoでは、フォームのサイズを変更すると、ラベルの更新が停止し、再起動することはありません。これは、MSの実装では発生しません。BeginInvoke
これ以上うまくいきません。さらに悪いことに、どちらの場合もUIがハングします。
この不一致がどこから来ているのか知っていますか?どのようにそれを解決しますか?そして最後に、BeginInvokeがここで機能しないのはなぜですか?私は大きな間違いを犯しているに違いありません...しかし、どれですか?
編集:これまでのいくつかの進歩:
- BeginInvokeを呼び出すことは、実際には機能します。ただ、UIが十分に速く更新されないため、停止しているように見えます。
- モノラルでは、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) {
}
}
}