Что не так с использованием Thread.Abort ()

Так что я знаю, что вы не должны использовать

Thread.Abort()

Но мне никогда не давали хорошее объяснение. Есть ли потеря производительности или какая-то скрытая ошибка?

Я знаю, что вы не можете игнорировать / проглотить исключение ThreadAbortException (что имеет смысл)

13.10.2009 10:01:57
Groo 13.10.2009 11:06:45
7 ОТВЕТОВ
РЕШЕНИЕ

В дополнение ко всем другим хорошим ответам здесь, позвольте мне добавить, что нет никакой гарантии, что вызов Thread.Abort фактически прервет рассматриваемый поток, когда-либо. Возможно (хотя и не особенно легко) «затвердеть» нить от прерывания. Если, например, вы прерываете поток, потому что считаете, что он выполняет враждебный код, тогда враждебный код может противостоять самому уничтожению.

Если у вас есть длительная операция с кодом, который вам не принадлежит, и который должен быть аккуратно удален, правильный способ сделать это - поместить этот код в свой собственный процесс , а не в собственный поток. (И предпочтительно в домене приложений с высоким уровнем безопасности в этом процессе.) Затем вы можете просто убить процесс.

Короче говоря, Thread.Abort в лучшем случае указывает на плохой дизайн, возможно, ненадежный и чрезвычайно опасный. Следует избегать любой ценой; единственный раз, когда вам стоит подумать об прерывании потока, это какой-то код «аварийного отключения», когда вы пытаетесь уничтожить домен приложения как можно более аккуратно.

84
13.10.2009 14:24:27
У меня есть одна из ситуаций, которые вы выделяете. Какой-то другой код (Консоль IronPython), который имеет функцию Run (...), которая должна выполняться в потоке. Кстати, у вас есть пример «ужесточения» темы?
Jan Bannister 13.10.2009 15:21:10
Выполните веб-поиск по «Ограниченным областям выполнения», и вы узнаете больше, чем хотите, о том, как возиться с распространением исключений прерывания потока.
Eric Lippert 13.10.2009 16:01:41
Разве вы не должны просто использовать, AppDomain.Unloadчтобы разрушить домен приложения? AppDomain.Unloadбудет вызывать Thread.Abortвсе темы, работающие в домене для вас.
Jordão 2.03.2011 17:15:20
Аааа, я понимаю, вы используете, Thread.Abortчтобы вы не получили, CannotUnloadAppDomainExceptionесли прерывание занимает некоторое время. Используя Thread.Abort, вы можете подождать, пока поток действительно прервется, и только потом вызывать AppDomain.Unload.
Jordão 2.03.2011 20:23:41
Вы интересуетесь, пытались ли вы синхронизировать поток ASP.NET WebForms.Abort () с помощью перенаправления, чтобы избежать запуска кода для остальной части страницы? : D
Quibblesome 2.01.2018 12:23:40

Thread.Abort останавливает вашу тему неконтролируемым образом. thread.Abort сгенерирует исключение, которое приведет к немедленной остановке вашего потока.

Что не так с этим: в большинстве случаев вы хотите аккуратно остановить выполняемую вами операцию. Например, если вы выполняете операцию ACID, вы можете завершить текущую операцию до завершения потока, чтобы ваша система оставалась в стабильном состоянии.

3
13.10.2009 10:04:45

Когда вы вызываете Thread.Abort () в другом потоке, в поток этого потока вводится исключение ThreadAbortException. Если вам повезет, код будет хорошо обработан и прервется в четко определенном состоянии. Проблема в том, что у вас нет возможности выяснить, повезет ли вам в каждом случае, поэтому, если вы предпочитаете безопасный, а не извинительный, вызов Thread.Abort в других потоках не является хорошей идеей.

5
13.10.2009 10:05:06

Потому что, если вы знаете, что поток находится в каком-то безопасном состоянии, в котором он может быть прерван, вы, несомненно, сможете лучше организовать связь и обеспечить чистый выход из потока.

Поток мог взять блокировку и быть в процессе изменения какого-либо общего состояния, а Thread.Abort отменит блокировку и оставит общее состояние поврежденным.

19
13.10.2009 10:33:37
Это можно предотвратить с помощью msdn.microsoft.com/en-us/library/… , хотя я бы посчитал это довольно хрупким!
Rob Fonseca-Ensor 13.10.2009 10:55:16
Можно обернуть тело вашего потока в try / finally, и они очистят ваши ресурсы в блоке finally. Но в целом я понимаю, что вы имеете в виду.
Jan Bannister 13.10.2009 15:15:45
@ RobFonseca-Ensor Не просто хрупкий. Вы когда-нибудь пытались написать безопасный код? Это делает простой потокобезопасность выглядит тривиальным. Это Abortможет произойти где угодно (в управляемом коде) - даже сам lockоператор на самом деле небезопасен. Таким образом, вы можете не только остаться с поврежденным состоянием, вы на самом деле можете иметь то, lockчто невозможно освободить - оно будет выпущено, когда поток, конечно, уйдет, но на самом деле этого не должно происходить никогда (до тех пор, пока процесс не завершится). умирает).
Luaan 20.05.2015 07:30:07
@JanBannister Это намного сложнее, чем вы думаете - вы должны понимать, что прерывание может произойти в любой части кода, даже в тех, где вы не ожидаете никаких исключений. Вы действительно можете написать finallyпредложение, которое правильно обрабатывает все это? Конечно, это можно сделать намного проще, избегая общего состояния и обновляя только общее состояние, когда он находится в безопасной, ограниченной области ... но тогда вы уже на пути к тому, чтобы уже не нуждаться в явном общем состоянии.
Luaan 20.05.2015 07:32:07

Thread.Abort вызывает исключение в целевом потоке. Тем временем целевой поток может выполнять некоторые критические операции, и возникновение исключения может нарушить состояние вашего приложения.

1
13.10.2009 10:05:41

Короче говоря. Любой объект IDisposable не может быть утилизирован. Любой заблокированный объект не может быть разблокирован. Все, что должно быть выполнено на 100%, никогда не будет выполнено.

10
13.10.2009 11:06:33
Все, что должно быть выполнено на 100%, рано или поздно выйдет из строя из-за отключения электроэнергии ...
gimpf 13.10.2009 11:15:55
Это неверно, Abortбудет выполнять finallyблоки и, следовательно, он будет уничтожать IDisposableи снимает любые блокировки по той же причине.
Sriram Sakthivel 16.04.2014 13:38:16
@ByteBlast Что ты имеешь в виду? использование выражения здесь не имеет значения. ключ finallyбудет работать. Неважно, используете вы usingзаявление или нет.
Sriram Sakthivel 1.05.2014 03:09:01
@SriramSakthivel: Я довольно поздно, чтобы сделать это исправление, но лучше поздно, чем никогда. Наконец блоки запускаются, только если попытка введена . using(acquire) body;есть { acquire; try { body } finally { dispose }}. Что если прерывание произойдет после шага получения, но до tryввода? Или, что еще хуже: что, если на этапе new Foo()получения конструктор открывает дескриптор файла и присваивает его полю; Что делать, если прерывание происходит после открытия, но до назначения ? Этот ответ абсолютно правильный; прерывание может привести к тому, что одноразовый ресурс останется нераспределенным.
Eric Lippert 31.01.2019 00:56:47
@SriramSakthivel: Кроме того, опять же, блокировки снимаются только в случае запуска . До C # 4 была возможность, что монитор был введен до блока try; в C # 4 мы изменили кодеген, чтобы предотвратить эту возможность. Но помните, некоторые люди пишут пары входа / выхода монитора без try-finally, и я бы сказал, что на самом деле это безопаснее; прерывание действительно может привести к тому, что монитор будет включен, но не завершен. Но это на самом деле не плохой случай. Плохой случай, когда мы входим в блокировку, мы изменяем состояние, чтобы нарушить инвариант, прерывать поток перед тем, как исправить, разблокировать и раскрыть мутацию!
Eric Lippert 31.01.2019 00:59:37

Обидеть себя легче. Как уже говорили другие, в коде возникает исключение, которое может произойти в любой момент. Это может быть хорошо, если вы ожидаете этого и закодировали таким образом, чтобы элегантно обрабатывать это исключение в любой момент, но некоторые люди этого не делают:

Monitor.Enter(obj);
// some code - if exception is raised here, then the lock isn't released
Monitor.Exit(obj)

IDisposable someCriticalResource = GetResource();
// some code - if exception is raised here, then the object isn't disposed
someCriticalResource.Dispose();

Кроме того, если вы работаете со многими людьми в команде, если у вас нет хороших обзоров кода, вы не можете гарантировать качество кода, с которым будете работать. Следовательно, лучше проповедовать «no Thread.Abort ()», чем заставлять людей помнить о написании кода, который устойчив к исключениям, возникающим в любом месте этого кода.

14
13.10.2009 12:26:04
Важным моментом здесь является то , что usingэто не прерывани безопасный либо - есть (крошечные) окно возможностей между созданием экземпляра и начало try-finallyблока. Это отличный рецепт для скрытых ошибок, которые вы никогда не сможете воспроизвести, и которые могут легко повредить ваши данные, повесить или убить ваше приложение и т. Д.
Luaan 20.05.2015 07:33:52