Вместо того, чтобы рабочий поток отправлял обновления в поток пользовательского интерфейса с помощью событий, рассмотрите возможность периодического извлечения (или опроса) потоком пользовательского интерфейса. Метод push хорош во многих ситуациях, но имеет два основных недостатка, которые работают против вас.
- Где-то существует дорогостоящая операция маршалинга, которая передает выполнение метода для безопасного выполнения обновлений пользовательского интерфейса (по крайней мере, должно быть).
- Рабочий поток получает возможность диктовать, как часто пользовательский интерфейс должен обновляться и, как следствие, сколько работы он должен выполнять. Это может легко сокрушить насос сообщений.
Я предлагаю использовать общую очередь, в которой рабочий поток ставит в очередь структуру данных, содержащую обновление, а поток пользовательского интерфейса удаляет и обрабатывает ее. Вы можете сделать так, чтобы поток пользовательского интерфейса опрашивал очередь через стратегически выбранный интервал, чтобы он никогда не зависал. Очередь будет выступать в качестве буфера, а не насоса сообщений интерфейса пользователя. Он будет уменьшаться и увеличиваться по мере увеличения и уменьшения количества обновлений. Вот простая диаграмма того, о чем я говорю.
[Worker-Thread] -> [Queue] -> [UI-Thread]
Сначала я бы начал с простого подхода к очереди, но вы могли бы перейти к следующему логическому этапу создания конвейера, в котором в потоке обновлений участвуют 3 потока. Рабочий поток ставит в очередь обновления, а поток пользовательского интерфейса удаляет их, как и раньше. Но новый поток может быть добавлен к миксу, который управляет количеством обновлений, ожидающих в очереди, и поддерживает его в управляемом размере. Это будет сделано путем пересылки всех обновлений, если очередь остается небольшой, но переключится в безопасный режим и начнет отбрасывать обновления, без которых вы можете жить, или объединять многие в одно, если можно определить разумную операцию объединения. Вот простая диаграмма того, как этот шаблон может работать.
[Worker-Thread] -> [Queue-1] -> [Pipeline-Thread] -> [Queue-2] -> [UI-Thread]
Опять же, начните с простого подхода с одной очередью. Если вам нужно больше контроля, перейдите к шаблону конвейера. Я успешно использовал оба.