DoEvents() зависает

Как удалить этот вопрос? Сначала я думал, что проблема связана с DoEvents, но, как оказалось, это не так. Я разместил вопрос здесь: http://goo.gl/VpAEK с более подходящим описанием проблемы.

Спасибо - я ценю любое руководство о том, как справиться с этим...


Во-первых, я знаю этот вопрос, поскольку общая концепция задавалась ранее - у меня есть (надеюсь) конкретный вариант, о котором можно спросить. Я также начну с того, что понимаю конкретные причины не использования Application.DoEvents() и заранее заверяю всех, что мы избегаем этого, когда это возможно, и используем несколько потоков для решения проблем (без Application.DoEvents()). участие .DoEvents()) во всем нашем приложении.

При этом он является частью структуры, и я думаю, что есть определенные ситуации, в которых он имеет место.

Конкретный случай, о котором я спрашиваю, - это ситуация с одним потоком, в которой задействован исключительно пользовательский интерфейс, где (как я понимаю) по определению - это нельзя сделать в фоновом потоке. В частности, мы загружаем/настраиваем ряд элементов пользовательского интерфейса в форме, что иногда занимает 1-2 секунды, и я хочу, чтобы во время этого процесса обновлялась метка, указывающая, что происходит. В фоновом потоке действительно нет никакой тяжелой работы/работы — все это пользовательский интерфейс.

Если у меня нет вызова Application.DoEvents() после изменения текста 4 метки, метка не перерисовывается. Если кто-то может предложить альтернативу, которая решает эту проблему по-другому в чисто пользовательском интерфейсе, в среде однопотокового - я весь внимание.

Проблема в том, что время от времени в тех случаях, которые я все еще пытаюсь определить, Application.DoEvents() просто не возвращается.

Я действительно понимаю все жалобы на метод DoEvents() (большинство из которых абсолютно справедливы!!!) и различные проблемы, которые он может вызвать! Итак, в идеале, не вдаваясь в огромные дебаты о плюсах и минусах вызова DoEvents (как, кажется, почти в любой другой ветке по этой теме) - конкретный вопрос, на который я пытаюсь ответить, - может ли кто-нибудь придумать какую-либо причину почему DoEvents просто зависнет? (т.е. не вернуть)?

Если вы хотите обсудить сам вызов DoEvents(), здесь есть отличное описание его сильных и слабых сторон: http://goo.gl/4BtZf

  • Наши пользователи сообщают, что это происходит не во время использования приложения, а только тогда, когда они на некоторое время отходят от своего компьютера (возможно, из-за экранной заставки?). Мы заметили это при изменении разрешения экрана во время удаленный просмотр компьютеров наших клиентов.
  • У нас есть пользователи, которые настаивают на том, что это происходит чаще, когда приложение свернуто.
  • У нас есть пользователи, которые настаивают на том, что это происходит чаще, когда приложение свернуто, и они выполняют некоторую работу в IE и/или Outlook.

Внутренне мы почти полностью не смогли воспроизвести его, за исключением сегодняшнего утра, когда я сделал все вышеперечисленное, в том числе отключил сетевое подключение на минуту или две и подключился к серверу через VPN на несколько минут - и все это в то время, когда наше приложение было свернуто.

После этого (буквально первый раз, когда нам удалось воспроизвести это дома) приложение зависло, а когда я подключился к процессу, оно зависло на строке Application.DoEvents(). 2-строчный метод:

label.Text = "Фу"; Приложение.DoEvents();

Многочисленные дополнительные тесты (попытки выполнить те же действия) не смогли воспроизвести проблему.

Какие-либо предложения? Спасибо.


Редактировать: Это табу, чтобы попытаться получить ответ на вопрос конкретно о DoEvents? Я относительно новичок в StackOverflow, и я просто немного смущен тем, почему я уже получил два голоса против.

Я видел, как этот вопрос задавали много раз в других темах, и (по крайней мере, на мой взгляд, почти универсальный ответ просто - не используйте application.DoEvents()). Я специально пытался быть внимательным в своем первоначальном вопросе и объяснить, почему мы использовали его в этом случае. В то же время я специально пытаюсь избежать еще одного обсуждения того, почему не следует использовать DoEvents. Если достаточное количество людей считают что-то плохой идеей, разве обсуждение этого в stackoverflow является табу? Опять же, я относительно новичок на этом форуме и пытаюсь понять правила этикета. Спасибо.


person eejai42    schedule 20.07.2012    source источник
comment
Вы пробовали label.Invalidate() или label.Refresh()?   -  person Alex Mendez    schedule 20.07.2012
comment
Я не думаю, что вы сможете поймать настоящего преступника без тщательного ведения журнала. Проблема в том, что Application.DoEvents() отправляет все ожидающие события своим обработчикам. Я думаю, лучшее, что вы можете сделать, это добавить как можно больше операторов ведения журнала, включить ведение журнала для нескольких ваших клиентов, а затем, когда приложение зависнет, проанализировать журналы и попытаться выяснить, какой конкретный обработчик вызывает проблему.   -  person Wiktor Zychla    schedule 20.07.2012
comment
Можете ли вы показать код, где вы обновляете метку?   -  person Alex Mendez    schedule 20.07.2012
comment
Это в вопросе. Это label.Text = foo; Приложение.DoEvents();   -  person eejai42    schedule 20.07.2012
comment
Я пробовал оба из них, и ни один из них не приводит к обновлению метки. Единственное, что я нашел, что дает UI время для рисования, это DoEvents().   -  person eejai42    schedule 20.07.2012
comment
возможный дубликат Application.Run(form) зависает   -  person Peter Ritchie    schedule 21.07.2012
comment
Особая проблема с Application.DoEvents заключается в том, что вы асинхронно просите платформу обрабатывать события, пока вы обрабатываете события. Если обработка события после вызова DoEvents блокирует то же самое, что и код, который может блокировать DoEvents, возникает взаимоблокировка (зависание). Если вы прекратите использовать DoEvents, зависание исчезнет (вы можете разобраться с почему вам нужны DoEvents позже).   -  person Peter Ritchie    schedule 21.07.2012


Ответы (1)


Неверно предполагать, что было бы неправильно использовать другие [фоновые] потоки для выполнения этой задачи. Если вы хотите пойти по пути Application.DoEvents, это нормально. Я не собираюсь сидеть здесь и говорить вам, что вы не должны использовать его, но вы должны, по крайней мере, рассмотреть возможность не использовать его как возможную альтернативу. Как вы сказали, вы обновляете большое количество различных элементов пользовательского интерфейса. Вы выполняете не одну задачу пользовательского интерфейса, вы выполняете много (десятки, сотни, тысячи, что угодно) задач. У вас также есть отдельная задача, отвечающая за управление всеми этими более мелкими задачами. Это управление меньшими задачами может выполняться либо в потоке пользовательского интерфейса, либо в потоке, отличном от пользовательского интерфейса. Если вы делаете это в потоке пользовательского интерфейса, пользовательский интерфейс блокируется до тех пор, пока не будет завершено каждое отдельное действие вложенного пользовательского интерфейса. Если у вас есть поток, не относящийся к пользовательскому интерфейсу, который действует просто как «планировщик», добавляя ряд более мелких задач пользовательского интерфейса для выполнения, тогда эти более мелкие задачи пользовательского интерфейса могут выполняться независимо и позволяют пользовательскому интерфейсу делать... что угодно... между некоторыми тех задач.

Вот пример этого:

private void button1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        for (int i = 0; i < 10; i++)
        {
            Invoke(new MethodInvoker(() => updateLabel(i)));
            Invoke(new MethodInvoker(() => longerUITask(i)));
        }
    });
}

private void longerUITask(int i)
{
    //do databinding that will take a second or two
    Thread.Sleep(1000);
}

private void updateLabel(int i)
{
    label1.Text = i.ToString();
}

Это будет менее эффективно. Да, это будет. Вы будете создавать другие потоки/задачи, управлять ими и т. д. Однако за эти деньги вы получаете простые и эффективные гарантии того, что пользовательский интерфейс останется отзывчивым.

person Servy    schedule 20.07.2012
comment
Интересные предложения - мне придется более подробно изучить варианты, которые вы предложили. Я раньше не использовал Task.Factory, это выглядит многообещающе. В одном из наших вызовов Application.DoEvents() он обновляет метку, как описано в исходном вопросе, прежде чем назначать свойство источника данных сторонней сетки данных, загрузка которой опять же иногда занимает 1-2 секунды. Применим ли в этом случае метод, предложенный выше? - person eejai42; 20.07.2012
comment
@eejai42 eejai42 Итак, я провел некоторое время, играя с этим, и это не очень хорошо сработало. Основная проблема заключается в том, что помпа сообщений всегда обслуживает запросы по порядку, она не выполняет более разумную работу по планированию задач, поэтому получается, что добавление 10 1-секундных заданий в очередь одновременно так же плохо, как добавление 1 10 вторая работа. Вам нужно добавить следующее 1-секундное задание после завершения предыдущего 1-секундного задания. Хотя вы, вероятно, можете найти способ сделать это с помощью Task, просто они не для этого были созданы. Приведенный выше код, который я редактировал, является самым простым, наиболее читаемым и эффективным из моего тестирования. - person Servy; 20.07.2012
comment
Спасибо Серви! Как оказалось, моя основная проблема в любом случае не может быть напрямую связана с командой DoEvents. Я продолжал тестировать, и иногда он зависает, когда НИ ОДИН из нашего кода не работает. Другими словами, когда я приостанавливаю приложение, оно находится в строке Application.Run(form) из program.cs, и НИКАКИХ других запущенных потоков!! Странно - да? По крайней мере, один раз был запущен поток, и он завис на строке Application.DoEvents, которая вызвала этот вопрос, но это (к сожалению?) непоследовательное поведение. Я разместил более конкретный вопрос здесь: goo.gl/j24cw - person eejai42; 20.07.2012
comment
Возможно, ответ на этот другой вопрос может ответить на этот вопрос, я отпишусь здесь, если это произойдет. В очередной раз благодарим за помощь. - person eejai42; 20.07.2012
comment
Как упоминалось ранее, это не имело НИЧЕГО общего с DoEvents. Полная остановка. Другой пост, который я создал после того, как понял, что он НЕ связан с DoEvents, можно найти здесь: goo.gl/j24cw. Ответ в этом посте предложил другой вопрос стека, в котором описывалось очень похожее поведение, и это звучало как результат создания элементов пользовательского интерфейса в потоке, отличном от пользовательского интерфейса. Это оказалось ИМЕННО тем, что происходило - и мой последний комментарий в другой статье дает более подробное объяснение, если кому-то интересно. СПАСИБО всем, кто заглянул сюда - я ценю помощь! - person eejai42; 26.07.2012