В блогах и т. д. есть сотни примеров того, как реализовать фонового рабочего, который регистрирует или сообщает статус переднему элементу GUI. Большинство из них включают подход к обработке состояния гонки, которое существует между порождением рабочего потока и созданием диалогового окна переднего плана с помощью ShowDialog (). Однако мне пришло в голову, что простой подход состоит в том, чтобы принудительно создать дескриптор в конструкторе формы, чтобы поток не смог инициировать вызов Invoke / BeginInvoke в форме до создания своего дескриптора.
Рассмотрим простой пример класса Logger, который использует фоновый рабочий поток для входа на передний план.
Предположим также, что мы не хотим, чтобы NLog или какой-либо другой тяжелый фреймворк делал что-то настолько простое и легкое.
] Окно моего регистратора открывается с помощью ShowDialog () потоком переднего плана, но только после запуска фонового «рабочего» потока. Рабочий поток вызывает logger.Log (), который сам использует logForm.BeginInvoke () для правильного обновления элемента управления журналом в потоке переднего плана.
public override void Log(string s)
{
form.BeginInvoke(logDelegate, s);
}
Где logDelegate - это просто простая оболочка вокруг «form.Log ()» или другого кода это может обновить индикатор выполнения.
Проблема заключается в существующем состоянии гонки; когда фоновый рабочий поток начинает вести журнал до того, как вызывается ShowDialog () переднего плана, дескриптор формы еще не создан, поэтому вызов BeginInvoke () завершается сбоем.
Я знаком с различными подходами, включая использование события Form OnLoad и таймер для создания рабочей задачи, приостановленной до тех пор, пока событие OnLoad не сгенерирует сообщение таймера, которое запускает задачу после отображения формы или, как упоминалось, с использованием очереди для сообщений. Однако я думаю, что простое принудительное создание дескриптора диалогового окна на раннем этапе (в конструкторе) гарантирует отсутствие состояния гонки, предполагая, что поток порождается тем же потоком, который создает диалоговое окно.
http://msdn.microsoft .com / en-us / library / system.windows.forms.control.handle (v = vs.71) .aspx
MSDN сообщает: «Если дескриптор еще не создан, ссылка на это свойство заставит дескриптор быть созданным ».
Итак, мой регистратор обертывает форму, а его конструктор делает:
public SimpleProgressDialog() {
var h = form.Handle; // dereference the handle
}
Решение кажется слишком простым, чтобы быть правильным. Меня особенно интересует, почему это, казалось бы, слишком простое решение безопасно или небезопасно для использования.
Есть комментарии? Я что-то упустил?
РЕДАКТИРОВАТЬ: Я НЕ прошу альтернативы. Не спрашивая, как использовать NLog или Log4net и т. Д., Если бы я был там, я бы написал страницу обо всех ограничениях клиентов в этом приложении и т. Д.
По количеству голосов за, есть много других людей, которые тоже хотел бы знать ответ.