I'm testing my app with mono in prevision of a Linux port, and I have a threading problem. I initially considered pasting 3000 code lines here, but finally I've devised a small minimal example ;)
You have a form with a button (poetically named Button1
, and a label (which bears, without surprise, the name Label1
)). The whole lot is living a happy life on a form called Form1
. Clicking Button1
launches an infinite loop that increments a local counter and updates Label1
(using Invoke
) to reflect its value.
Now in Mono, if you resize the form, the label stops updating, never to restart. This doesn't happen with MS implementation. BeginInvoke
doesn't work any better; worse, it makes the UI hang in both cases.
Do you know where this discrepancy comes from? How would you solve it? And finally, why doesn't BeginInvoke work here? I must be making a huge mistake... but which?
EDIT: Some progress so far:
- Calling BeginInvoke does in fact work; only, the UI just doesn't refresh fast enough, so it seems to stop.
- On mono, what happens is that the whole thread hangs when you insert a message in the UI queue (eg by resizing the form). In fact, the synchronous
Invoke
call never returns. I'm trying to understand why. - Of interest: even using
BeginInvoke
, the asynchronous calls don't get executed before the resizing operation ends. On MS.Net, they keep running while resizing.
The code looks like this (C# version lower):
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
Or, in 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) {
}
}
}