Страницы

Поиск по вопросам

пятница, 12 июля 2019 г.

Корректное закрытие фонового загрузчика

У меня есть компонент, который подгружает данные в фоне. Всё грузится в отдельном потоке, а обращения к форме, когда данные загружены, происходят через ISynchronizeInvoke. Компонент подписывается на событие FormClosed формы, на которой он лежит, чтобы после закрытия прибивать загрузчик установкой флага, по которому завершается поток загрузки. Проблема в том, что это не всегда помогает. Иногда получается так, что обращение к форме происходит уже после того, как форма закрылась, и поток загрузки виснет на вызове ISynchronizeInvoke.Invoke. Это может возникнуть тогда, когда флаг, по которому проверяется завершение потока загрузки, ещё не установлен перед обращением к форме, но в момент обращения к форме он уже установлен, и форма закрылась. Я попробовал сделать блокировку на проверке флага с обращением к форме и на обработчике закрытия формы, стало получше. Где-то на полгода об этом баге мы забыли - не беспокоил. Но недавно на тормозной машине в этом месте словили взаимную блокировку. Сценарий такой: Фоновый поток захватил блокировку и обратился к форме Обработчик закрытия формы вызвался раньше метода обновления формы, вызванного из потока загрузки Обработчик закрытия формы пытается захватить блокировку и встаёт в очередь, так как блокировка захвачена фоновым потоком Но и фоновый поток ожидает ответа от пользовательского интерфейса, так как вызвал ISynchronizeInvoke.Invoke Не хотелось бы использовать грубые методы вроде Thread.Abort.


Ответ

В общем, проблему решил так: вместо Invoke вызываю BeginInvoke - EndInvoke, между ними делаю цикл, в котором в течение 100 миллисекунд жду завершения обработки вызова и проверяю флаг завершения. Если флаг завершения установлен, выхожу без EndInvoke

Комментариев нет:

Отправить комментарий