Я пишу плагин для другой программы, которая использует собственную программу, чтобы открыть серию файлов для извлечения некоторых данных. Одна из проблем, с которой я столкнулась, - это процесс, который занимает много времени, и я хочу, чтобы пользовательский интерфейс не висел. Кроме того, я также хочу дать пользователю возможность отменить процесс до его завершения. Раньше я использовал фонового работника для этого типа вещей, но в этом случае я не думаю, что BackgroundWorker будет работать.
Чтобы создать подключаемый модуль через API, который я использую, можно создать пользовательскую команду путем наследования с интерфейса IAPICommand. Этот интерфейс включает в себя метод Execute (приложение). Затем создается экземпляр класса, и метод Execute() вызывается программой, когда пользователь вызывает пользовательскую команду в программе.
Метод Execute() передается ссылка на текущий объект приложения, когда он вызывается, и именно этот объект приложения используется для открытия файлов для извлечения данных. Тем не менее, экземпляр приложения не может открыть документ по запросу потоком другого исходного потока Execute().
Таким образом, обычно пользовательский интерфейс будет существовать в основном потоке, а извлечение времени, затрачиваемое на обработку данных, будет выполняться на вторичном потоке. Однако в этом случае извлечение данных должно выполняться в основном потоке, и мне нужно создать дополнительный поток для пользовательского интерфейса.
Здесь урезанная версия кода.
class MyCommand:IAPICommand
{
public void Execute(Application app) // method from IAPICommand
{
Thread threadTwo= new Thread(ShowFormMethod);
threadTwo.Start();
}
public void ProcessWidget(Widget w, Application app)
{
//uses an App to work some magic on C
//app must be called from the original thread that called ExecuteCommand()
}
//method to open custom form on a seperatethread
public void ShowFormMethod()
{
MyForm form = new MyForm();
form.ShowDialog();
}
}
Вот блок-схема, которая показывает, как я думаю, что это должно в конечном итоге работать.
alt text http://dl.dropbox.com/u/113068/SOMLibThreadingDiagram.jpg
- Имеет ли смысл эта диаграмма, и если я даже принимаю правильный подход для решения этой проблемы?
- Как только основной поток запускает поток пользовательского интерфейса, я хочу, чтобы он дождался, когда пользователь либо выберет виджеты для обработки, либо завершает команду, закрывая форму (красные цифры на диаграмме). Как я могу заставить главный поток ждать, и как я могу заставить его продолжить обработку или продолжить до конца, когда заканчивается конец пользовательского интерфейса? Я думал, что я могу заставить основной поток ждать блокировки монитора. Затем поток пользовательского интерфейса заполняет статический список виджетов, которые будут обрабатываться, а затем пульсирует основной поток, чтобы инициировать обработку. Поток пользовательского интерфейса также будет пульсировать главный поток, когда форма закрыта, и основной поток знал бы, чтобы он продолжал до конца команды, если он когда-либо пульсировал, когда список виджета обрабатывался пустым.
- Как разрешить основному потоку сообщать о ходе или завершении обработки виджета обратно в поток пользовательского интерфейса (желтые стрелки на диаграмме)? Я просто использовал метод BeginInvoke() формы для этого?
- Как разрешить потоку пользовательского интерфейса отменить обработку виджета (зеленая стрелка на диаграмме)? Я думаю, что я мог бы настроить статический логический флаг, который проверяется перед обработкой каждого виджета?