Работает один или несколько потоков. Нажимаем кнопку “Закрыть”. Программа падает, потому что потоки продолжают работать и очень хотят синхронизироваться с формой, а её больше нет.
Собственно, больной вопрос: Как этого избежать?
В потоке можно ловить System.ComponentModel.InvalidAsynchronousStateException, тогда ошибки нет. Но это как-то тупо - на каждый чих ловить экскепшен
public void Work(object context)
{
synchronizationContext = (SynchronizationContext)context;
...
Как проверить, что поток этого контекста ещё существует?
Но это не главная проблема. Когда форма закрывается, она никого не ждет. А значит, обработчик события завершения потока не выполнится. А в нём может быть что-то важное.
Ну по идее программа должна знать поименно все задачи которые решаются в текущий момент и предполагать их нормальное завершение.
Есть Токен завершения который можно раздавать во все потоки и в цикле обработки проверять и обрабатывать корректно выход.
Ну так за потоками-то следить надо, а не просто запустил и забыл )
Например добавлять их в какой-нибудь список, при завершении потока удалять его из списка, смотреть не пуст ли.
А следить как? Знаю, что при закрытии формы можно проверять список. Если он не пуст, то не давать закрыться. Это самая примитивная защита от дурака. Но потоки ведь могут вовсе не завершиться и форму закрыть вообще не получится.
А как ещё за ними следить?
То есть, при закрытии формы отменяем закрытие и переключаем какой-нибудь флаг в true. А при завершении потока, если этот флаг true пытаемся закрыться. А там опять проверяется список, и так пока список не пуст.
Так чтоли?
Например, подключение к какому-нибудь URL иногда может занимать 40 секунд. И что тогда делать? А бывает, что вообще напрочь виснет.
CancellationToken выставляете и все. В циклах каждого из потоков делаете условие
While(!CancelToken.CancelRequested)
{
do work
}
При закрытии формы в лоб выставляете CancelRequest и все кто связан с этим объектом автоматически выйдет из своих циклов работы. Зачем тут что то придумывать с фалагми.
Task запускать с тем же самым токенов завершения. Ведь именно для этого он и придуман. И между потоками отлично работает.
Он специально разработан для оповещения. Если один раз его выставить как requested то обратно его уже не вернуть. Это потокобезопасная замена вашему флагу bool.
А чего нет то. Делаете дополнительный флаг типа ProgramClosing; При закрытии программа проверяет этот флаг. Если он истина значит подразумевается что программа сама все закончила и завершает работу без запроса пользователя.
То есть. Завершаете прогу с флагом false, программа видит что это пользователь завершает, проверяет потоки если они работают то отменяет закрытие и выдает диалог ожидания, в тоже время сообщает любым способом о требовании закрыться… либо это будет токен который изначально передан в потоки либо это какой то другой способ. После того как потоки завершили работу программа выставляет флаг ProgramClosing в истину и закрывается. В обработчике закрытия видим что флаг в истине значит не тормозим его и завершаем всю работу приложения.
А кто этот флаг в true установит? То есть, при завершении потока удалять его из списка, и если список пуст ставить true. А перед запуском потоков делать false.
Правильно понял?
Функция которая будет контролировать завершение всех потоков.
Функция запустится когда пользователь нажмет закрыть программу, проследит что все закрылись и повторит закрытия с флагом чтобы в событии закрытия окна она не вызвалась вновь.
А контроллировать-то как? Надо же не просто всех убить и закрыться, а подождать завершения и только тогда закрыться.
Если просто кинуть CancelRequested, то форма всё-равно закроется сразу и не будет ждать, пока завершатся все потоки.
А как именно она узнает, что все потоки завершились?