control.BeginInvoke () Vs Диспетчер Vs SynchronizationContext Vs .. - НАДЕЖНОСТЬ - PullRequest
6 голосов
/ 13 июня 2011

Вызов потока пользовательского интерфейса из рабочего потока обсуждался много раз, и мы знаем, почему следует использовать BeginInvoke () вместо Invoke (). Недавно я опубликовал этот вопрос и после некоторых исследований я обнаружил, что существует как минимум три различных способа (внутренне они могут быть одинаковыми) для вызова (асинхронно) чего-либо в потоке пользовательского интерфейса.

  1. Control.BeginInvoke()
  2. Использование SynchronizatoinContext Класс
  3. Использование Dispatcher.BeginInvoke(priority.. )

Может кто-нибудь сказать мне, какой НАДЕЖНЫЙ способ асинхронно вызывать метод, который будет выполняться в потоке пользовательского интерфейса. Есть опыт? Я вижу, что Dispatcher.BeginInvoke имеет приоритетный компонент, делает его более надежным?

Контекст
мы используем someControl.BeginInvoke(), но заметили, что иногда (к сожалению, только в рабочей среде конечного пользователя) делегат переходит к BeginInvoke is, никогда не выполняющемуся, что заставляет меня поверить, что создаваемое им почтовое сообщение теряется. Нам нужен надежный способ связи с потоком пользовательского интерфейса. control.Invoke() иногда вывешивают пользовательский интерфейс, поэтому мы тоже не хотим туда заходить.

Ответы [ 3 ]

0 голосов
/ 13 декабря 2012

SynchronizationContext является более абстрактным и адаптируемым в большинстве случаев.Это обертка конкретной реализации.MSDN говорит, что «провайдеры моделей синхронизации могут расширять этот класс и предоставлять свои собственные реализации для этих методов».

0 голосов
/ 12 июня 2013

Вы должны быть осторожны с лямбда-функциями и BeginInvoke. У меня был такой код, который приводил ко всякому странному поведению.

MyThing thing;
while( GetThing(ref thing)) {
    control.BeginInvoke((Action)(() => control.Text = thing.ToString()));
}

Проблема в том, что thing не оценивается при создании лямбда-функции. Он оценивается при выполнении функции lamdba. Но он связан с переменной, которая одновременно изменяется в потоке производителя.

Вы можете решить эту проблему, объявив копию локальной переменной thing

MyThing thing;
while( GetThing(ref thing)) {
  MyThing thing_x = thing;
  control.BeginInvoke((Action)(() => control.Text = thing_x.ToString()));
}

Или вы можете положить уродство BeginInvoke в оболочку

MyThing thing;
while( GetThing(ref thing)) {
  SetText(thing);
}

void SetText(MyThing thing)
  control.BeginInvoke((Action)(() => control.Text = thing.ToString()));
}
0 голосов
/ 13 июня 2011

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...