При использовании Parallel BeginInvoke работает, а Invoke нет - c # 4.0 - PullRequest
3 голосов
/ 02 октября 2011

Когда я использую invoke внутри функции AddListBoxItem, как показано ниже, программное обеспечение перестает отвечать и замораживается, но если я использую BeginInvoke , оно работает.Почему это происходит?

visual studio 2010, C # 4.0

 private void button2_Click(object sender, EventArgs e)
{
    var watch = Stopwatch.StartNew();
    Parallel.For(2, 20, (i) =>
    {
        var result = SumRootN(i);
        AddListBoxItem("root " + i + " : " + result);
    });
    AddListBoxItem(watch.ElapsedMilliseconds.ToString());            
}

private delegate void AddListBoxItemDelegate(object item);

private void AddListBoxItem(object item)
{
    if (this.listBox1.InvokeRequired)
    {
        this.listBox1.Invoke(new AddListBoxItemDelegate(this.AddListBoxItem), item);
    }
    else
    {
        this.listBox1.Items.Add(item);
    }
}

Ответы [ 3 ]

3 голосов
/ 03 октября 2011

Звучит так, как будто вы блокируете поток пользовательского интерфейса.Это имеет смысл, поскольку ваш button2_Click не завершается до тех пор, пока не завершится For, а , в частности , никакие события цикла обработки сообщений не могут быть обработаны до тех пор, пока не завершится button2_Click.Если вы находитесь в другом потоке, Invoke использует событие цикла сообщений и не возвращает до тех пор, пока этот элемент не будет обработан - так что ничего не будет сделано - и For / button2_Clickникогда не завершать.

Используя BeginInvoke, вы просто очередь эта работа - BeginInvoke немедленно возвращается.Это означает, что For может завершиться, что позволяет завершить button2_Click, что , а затем позволяет обрабатывать события цикла сообщений (обновляя пользовательский интерфейс).

3 голосов
/ 02 октября 2011

Ваш поток пользовательского интерфейса будет ждать завершения Parallel.For, прежде чем продолжить.Это означает, что он не может обрабатывать дальнейшие сообщения пользовательского интерфейса до тех пор, пока он не будет завершен.

Теперь, когда рабочие потоки вызывают Invoke, они ждут, пока поток пользовательского интерфейса не обработает делегат, прежде чем продолжить.Таким образом, они ожидают, что поток пользовательского интерфейса освободится, в основном.

Следовательно, у вас есть тупик - поток пользовательского интерфейса ожидает задачи, которые ожидают поток пользовательского интерфейса ... BeginInvokeработает, потому что тогда потоки задач не ждут обработки делегатов в потоке пользовательского интерфейса.

Я бы посоветовал вам не вызывать Parallel.For в потоке пользовательского интерфейса дляначать с.Вы будете блокировать пользовательский интерфейс до тех пор, пока он не завершится, что не очень хорошая идея.Делайте все это в фоновом потоке - тогда вы все равно можете использовать Invoke, если хотите, и пока он выполняет вычисления, пользовательский интерфейс все равно будет отзывчивым.

1 голос
/ 03 октября 2011

Я думаю, это связано с тем, что Mainthread блокируется в указанном выше событии Click, ожидая завершения AddListBoxItem, который ожидает возврата события buttion2_click.
Вы не должны иметь логику контроллера в своем пользовательском интерфейсе, поэтому основная проблема в том, что Click не вызывает обратную логику в другом потоке.

После реализации потока для вашей логики ваш графический интерфейс не будет блокироваться и будет легко обновляться в любой ситуации.

...