Поаккуратнее с топором. Часть 2. А как насчет исключений?
Предположим, вы завершаете выполнение рабочего потока, о чем мы говорили в прошлый раз, и поток генерирует исключение. Что будет в этом случае?
Неприятности, вот что будет. Что же можно сделать в этой ситуации?
Как и в предыдущем случае, лучше всего вообще не попадать в эту ситуацию: пишите код в рабочих потоках таким образом, чтобы он не генерировал исключений. Если вы не можете этого сделать, тогда у вас есть два варианта: обрабатывать исключение или не обрабатывать исключение.
Предположим, вы не будете обрабатывать исключение. Если говорить о CLR v2, то необработанное исключение в рабочем потоке приведет к завершению всего приложения. Причина такого поведения заключается в том, что в прошлом бывали случаи запуска нескольких рабочих потоков, все они генерировали исключения, в результате оставалось работающее приложение без единого рабочего потока, которое ничего не делало и не говорило об этом пользователю. Гораздо лучше заставить автора кода обработать ситуацию, при которой рабочий поток завершается вследствие исключения. При работе по старинке ошибки эффективно скрываются и легко написать ненадежное приложение.
Предположим, вы обработали исключение. Что теперь? Некоторый код в другом потоке сгенерировал исключение, которое, по определению, является непредвиденным, исключительным ошибочным условием. Теперь у вас нет ни малейшего понятия о том, находятся ли ваши данные в согласованном состоянии и сохранены ли инварианты в ваших подсистемах. Так что же вы собираетесь делать теперь? Едва ли вы можете безопасно предпринять что-либо в такой ситуации.
Вопрос в том, «что же лучше всего для пользователя в такой неприятной ситуации?» Ответ зависит о того, что делает конкретное приложение. Вполне возможно, что в этой ситуации лучше всего принудительно закрыть приложение и сказать пользователю о том, что произошел непредвиденный сбой. Это может быть гораздо лучше, чем пытаться что-либо сделать, тем самым усугубляя ситуацию путем, скажем, непреднамеренного уничтожения данных пользователя при попытке выполнения очистки ресурсов.
Или, вполне возможно лучшее, что можно сделать – это предпринять честную попытку сохранить данные пользователя, максимально очистить состояние и закрыть приложение насколько возможно нормальным образом.
Оба сегодняшних вопроса, а также вопрос, заданный в прошлый раз, являются частными случаями более общего вопроса: «Что мне делать, когда моя подсистема, выполняемая в отдельном потоке, ведет себя некорректно?» Если эта подсистема ненадежна, тогда либо сделайте ее надежной, либо выработайте политику, каким образом вы будете работать с ненадежными подсистемами, и реализуйте приложение в соответствии с этой политикой. Я знаю, что это весьма туманный ответ, но это, прежде всего потому, что работа с ненадежными подсистемами – это чрезвычайно неприятная ситуация. Способы работы с такими подсистемами зависят от природы ненадежности и последствий этой ненадежности для ценности пользовательских данных. К сожалению, на этот вопрос не существует универсального ответа.