Как я могу обнаружить исключение ThreadAbortException в блоке finally? (.СЕТЬ) - PullRequest
8 голосов
/ 09 декабря 2008

У меня есть некоторая критическая логика в блоке finally (с пустым блоком try), потому что я хочу гарантировать, что код будет выполнен, даже если поток будет прерван. Однако я также хотел бы обнаружить исключение ThreadAbortException. Я обнаружил, что упаковка моего критического блока try / finally в try / catch не перехватывает исключение ThreadAbortException. Есть ли способ обнаружить это?

try {
    try { }
    finally {
        // critical logic
    }
} catch(Exception ex) {
    // ThreadAbortException is not caught here, but exceptions thrown
    // from within the critical logic are
}

Ответы [ 7 ]

8 голосов
/ 03 марта 2011

Это любопытная проблема.

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

Итак, я хотел обнаружить исключение с помощью этого:

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = false;
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

(Мой настоящий код только что спал в этом критическом разделе кода, поэтому я мог быть уверен, что он наконец прекратит работу.)

напечатано:

Тема прервана? Ложные

Хммм, действительно странно!

Так что я подумал о том, чтобы сделать немного больше работы, чтобы обмануть любую «умную» оптимизацию:

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = AmIEvil();
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

Где AmIEvil просто:

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AmIEvil() {
  return false;
}

Наконец напечатано:

Тема прервана? Правда

И вот оно у вас есть. Используйте это в своем коде:

try {
  try { }
  finally { /* critical code */ }
  NoOp();
}
catch (Exception ex) {
  // ThreadAbortException is caught here now!
}

Где NoOp просто:

[MethodImpl(MethodImplOptions.NoInlining)]
static void NoOp() { }
3 голосов
/ 09 декабря 2008

На самом деле вы можете выполнить код в операторе catch просто отлично для ThreadAbortException. Проблема в том, что исключение будет переброшено, как только выполнение покинет блок catch.

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

ThreadAbortException

2 голосов
/ 19 ноября 2011

Если вызов Thread.Abort плохой дизайн, почему SQL Server вызывает его в потоке, на котором выполняется код пользователя? Потому что именно так обрабатывается отмена запроса, и это вызывает кошмары.

2 голосов
/ 09 декабря 2008

Не думаю, что это возможно.

Зачем вам нужно обрабатывать ThreadAbortException в первую очередь? Вызов thread.Abort () обычно является признаком плохого дизайна. Иметь переменную-флаг, которая при значении true будет просто возвращать; из функции потока после соответствующей очистки, конечно.

Таким образом, вам не нужно беспокоиться об исключении.

2 голосов
/ 09 декабря 2008
0 голосов
/ 02 марта 2009

Вы пробовали что-то подобное?

try {
    try { }
    catch (ThreadAbortException)
    {
      ThreadAbortExceptionBool = true;
    }
    finally {
        // critical logic
        if (ThreadAbortExceptionBool)
          // Whatever
    }
} 
catch(Exception ex) {
    // ThreadAbortException is not caught here, but exceptions thrown
    // from within the critical logic are
}
0 голосов
/ 11 декабря 2008

Я согласен с Арулом. Вызов Thread.Abort () является признаком плохого дизайна.

Позвольте мне процитировать Питера Ричи из MSDN: Thread.Abort (выделение мое):

Существует множество причин не использовать Thread.Abort и ThreadAbortException

На некоторых платформах (например, x64 и IA64) прерывание может произойти до Monitor.Enter и блока try (даже с блокировкой / SyncLock), оставляя монитор потерянным. ThreadAbortException может возникать в стороннем коде, не написанном для обработки прерывания потока. Поток может быть прерван во время обработки блока finally в .NET 1.x Использует исключения для нормальной логики потока управления. Асинхронное исключение может прервать изменение состояния или ресурсов сегмента, оставляя их поврежденными.

Подробнее см .:
http://msmvps.com/blogs/peterritchie/archive/2007/08/22/thead-abort-is-a-sign-of-a-poorly-designed-program.aspx
http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
http://blogs.msdn.com/ericlippert/archive/2007/08/17/subtleties-of-c-il-codegen.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...