Приложение работает в несколько потоков. Если пользователь желает завершить приложение, закрывая основную форму, то остальные потоки нельзя рубить по Thread.Abort так как это приводит к ошибкам API и повреждению данных. Соответственно сделал в классах тех потоков свойство Stop, которое можно выставить в false и соответственно произойдет корректное завершение работы. Выглядит это примерно так:
class ShowOnMap{
...
private bool stop = false;
object thisLock = new object();
public bool Stop {
get{return stop;}
set{lock(thisLock){stop = value;}}
}
...
public void Show()
{
...
while(... && !stop){
...
lock(thisLock){
...
}
...
}
}
}
Обработчик закрытия формы (а это означает, что пользователь хочет завершить приложение) выглядит примерно так:
if (thrShowOnMap != null){ // Проверка, что поток работающий с классом ShowOnMap существует
showOnMap.Stop = true; // Сигнализация о необходимости завершить работу объекту класса ShowOnMap
thrShowOnMap.About(); // Попытка прерывание поток (должно произойти после корректного прекращения работы объекта класса ShowOnMap
Thread.Sleep(1000); // Ожидание, для корректного завершения потока
}
Все это дело достаточно успешно работало, но поскольку потоков было несколько, то для каждого в закрытии формы был прописан соответствующий код завершения (там разные классы в разных потоках работают). И время закрытия формы было никак не меньше чем количество потоков помноженное на одну секунду (Thread.Sleep(1000). Рассудив, что это неправильно — пользователь жмет заркрыть форму, а она продолжает висеть на экране и ни на что не реагировать в течении нескольких секунд, я вынес процесс прекращения обработки данных и остановки потоков в отдельный поток, специально созданный для этой цели. Форма же закрывалась сразу. Таким образом, после закрытия формы, приложение на самом деле еще работает несколько секунд и при желании пользователь может его наблюдать в списке процессов. Меня это не смущает. Однако хочу знать, что остальные разработчики думают о таком подходе?
Здравствуйте, Аноним, Вы писали:
А>Соответственно сделал в классах тех потоков свойство Stop, которое можно выставить в false и соответственно произойдет корректное завершение работы.
Почему не сделано "по-человечески" с использованием, например, ManualResetEvent?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Аноним, Вы писали:
>>>...Однако хочу знать, что остальные разработчики думают о таком подходе?
Ага, знакомая история. Проблема может быть в том, что какой-то из потоков просто зависнет при закрытии (или уже висел) — тогда Ваша прога будет вечно ждать окончания работы, занимая ресурсы. Так что не стоит отказываться от Abort; один из вариантов — завести обертку над ThreadPool и сделать перегруженный вариант EnqueueWorkItem с параметром TimeStamp timeout.
Ну и при завершении все-таки лучше показать пользователю, что прога еще работает.
Впрочем, дело хозяйское
На опушке за околицей мужики строили коровник.
Работали споро и весело. Получалось х**во.
Re[2]: Завершение многопоточного приложения
От:
Аноним
Дата:
07.11.07 10:15
Оценка:
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, Аноним, Вы писали:
А>>Соответственно сделал в классах тех потоков свойство Stop, которое можно выставить в false и соответственно произойдет корректное завершение работы.
_FR>Почему не сделано "по-человечески" с использованием, например, ManualResetEvent?
Не умею. Никогда с потоками раньше не работал.
А что собственно ManualResetEvent изменит? Если я правильно понимаю, то всего лишь будет переданна информация о наступлении некоего события.
Здравствуйте, Аноним, Вы писали:
_FR>>Почему не сделано "по-человечески" с использованием, например, ManualResetEvent? А>Не умею. Никогда с потоками раньше не работал.
Вот тебе и повод изучить и опробовать. Начать советую с какой-нить книги Рихтера, Джефри.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, <Аноним>, Вы писали: А>Все это дело достаточно успешно работало, но поскольку потоков было несколько, то для каждого в закрытии формы был прописан соответствующий код завершения (там разные классы в разных потоках работают). И время закрытия формы было никак не меньше чем количество потоков помноженное на одну секунду (Thread.Sleep(1000).
Поэтому вместо пристрелки потоков по очереди, нужно делать так:
1. Оповещаем все потоки о том, что пора закрываться.
2. Ждем все потоки в течение некоторого таймаута (например, 10 секунд).
При помощи WaitForMultipleObjects.
3. Тех, кто не успел стопнуться добровольно, придется пристрелить.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.