Проблема с потоками, при которой моно зависает, а MS.Net - нет

Я тестирую свое приложение с моно в предвидении порта Linux, и у меня проблема с потоками. Сначала я подумал о том, чтобы вставить сюда 3000 строк кода, но в конце концов придумал небольшой минимальный пример; )

У вас есть форма с кнопкой (поэтическое название Button1 и меткой (которая, что неудивительно, носит имя Label1 )). Все живут счастливой жизнью в форме под названием Form1 . Нажатие на Button1 запускает бесконечный цикл, который увеличивает локальный счетчик и обновляет Label1 (используя Invoke ), чтобы отразить его значение.

Теперь в Mono, если вы измените размер формы, метка перестает обновляться, никогда не перезапускается. Этого не происходит с реализацией MS. BeginInvoke работает не лучше; Хуже того, в обоих случаях пользовательский интерфейс зависает.

Вы знаете, откуда взялось это несоответствие? Как бы вы ее решили? И наконец, почему здесь не работает BeginInvoke? Я, должно быть, совершаю огромную ошибку ... Некоторый прогресс на данный момент:

  • Вызов BeginInvoke действительно работает; только пользовательский интерфейс просто не обновляется достаточно быстро, поэтому кажется, что он останавливается.
  • В монофоническом режиме происходит то, что весь поток зависает, когда вы вставляете сообщение в очередь пользовательского интерфейса (например, изменяя размер формы). Фактически, синхронный вызов 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) {
        }
    }
}
7
задан Clément 27 April 2011 в 16:53
поделиться