Я пишу плагин для другой программы, которая использует родную программу, чтобы открыть серию файлов для извлечения некоторых данных. Одна из проблем, с которой я столкнулась, - это процесс, который занимает много времени, и я хочу, чтобы пользовательский интерфейс не висел. Кроме того, я также хочу дать пользователю возможность отменить процесс до его завершения. Раньше я использовал фонового работника для этого типа вещей, но в этом случае я не думаю, что 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() формы для этого?
- Как разрешить потоку пользовательского интерфейса отменить обработку виджета (зеленая стрелка на диаграмме)? Я думаю, что я могу настроить статический логический флаг, который проверяется перед обработкой каждого виджета?
Как отметил Джон, ваша жизнь будет намного проще, если вы будете использовать все свои материалы в основном потоке пользовательского интерфейса и делегируете тяжелую обработку фоновым потокам. В этом сценарии общение легко осуществляется с помощью методов Control.Invoke – mfeingold
Как можно отменить обработку, если поток, который вы должны использовать для переадресации в приложение, занят обработкой и недоступен для вас? Можете ли вы отменить второй поток, но не обрабатывать второй поток? –
Да, пользователь запросит отмену во втором (UI) потоке, чтобы отменить обработку в основном потоке приложения. –