2010-01-18 5 views
1

Снова я хочу поговорить о безопасности функции Thread.Abort. Мне было интересно каким-то образом прервать операции, которые я не могу контролировать, и не хочу на самом деле, но я хочу, чтобы мои потоки были бесплатными как можно скорее, чтобы предотвратить поток, жаждущий моего приложения.. NET Thread.Abort снова

Таким образом, я написал несколько тестовых кодов, чтобы узнать, можно ли использовать Thread.Abort и отменить прерывание потока. Вот код:

int threadRunCount = 0; 
int threadAbortCount = 0; 
int threadFinallyCount = 0; 
int iterations = 0; 

while(true) 
{ 
Thread t = new Thread(() => 
{ 
    threadRunCount++; 
    try 
    { 
    Thread.Sleep(Random.Next(45, 55)); 
    } 
    catch(ThreadAbortException) 
    { 
    threadAbortCount++; 
    } 
    finally 
    { 
    threadFinallyCount++; 
    } 
}); 

t.Start(); 
Thread.Sleep(45); 
t.Abort(); 

iterations++; 
} 

Так, до сих пор этот код работал в течение примерно 5 минут, и threadRunCount всегда было равен threadFinally и threadAbort был несколько ниже, в количестве, потому что некоторые нити выполнены без прерывания или, возможно, были прерваны в конце концов ,

Итак, вопрос в том, что-то пропустить?

ответ

4

С помощью надуманного теста вы можете доказать что угодно.

Все, что вы доказали, так это то, что с Код, который вы написали для вашего теста, Thread.Abort, похоже, работает нормально.

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

Например, попробуйте этот код:

using (Stream stream = new FileStream(@"C:\Test.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None)) 
{ 
    Thread.Sleep(Random.Next(45, 55)); 
} 

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

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

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

Например, вы на самом деле ожидать, что следующий код аварии после КРП-выражение была оценена, но перед темDispose -Call прошел?

if (_ObjectToDispose != null) 
{ 
    _ObjectToDispose.Dispose(); 
    _ObjectToDispose = null; 
} 

Что делать, если это происходит сразу после вызова .Dispose? Поле будет по-прежнему иметь ненулевое значение, что может привести к тонким проблемам в другом месте.

Что делать, если вы сделаете это:

IDisposable objectToDispose = Interlocked.Exchange(ref _ObjectToDispose, null); 
if (objectToDispose != null) 
    objectToDispose.Dispose(); 

С помощью этого кода вы захватить значение, заменяет его нулем, а затем, прежде чем вы получите вокруг вызова Dispose, ваш ThreadAbortException случается, что будет просто оставить объект.

Позвольте мне водить точки дома:

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

Если вам не нужно планировать ошибки в своем будущем графике. В этом случае идите прямо вперед и используйте Thread.Abort, потому что я могу почти гарантировать, что у вас будут проблемы.

+0

Я попытался запустить код, который вы упомянули, с открытием файла, и да в какой-то момент после создания нового потока файл по-прежнему занят другим потоком, который должен быть прерван на самом деле, но что, если потоки не будут использовать общие ресурсы? Кажется, это просто доказывает, что нить Abort несколько небезопасна. Даже если мне просто нужно прекратить применение приложения, не удалось прервать процесс зависания или утечки памяти, если был запущен какой-то неуправляемый код? В моем случае мне нужно что-то, что может ограничить время выполнения процесса до предельного предела времени ожидания, и в моем случае я не могу контролировать выполнение этого процесса. Любые идеи по этому делу? – hoodoos

+0

Вы должны задать другой вопрос о SO, как ограничить время выполнения, а затем опубликовать то, что вы намереваетесь сделать в этом коде. В некоторых случаях в качестве примера не удастся выполнить то, что вы хотите, если код занят неуправляемым кодом. Единственным «безопасным» способом сделать это было бы создание подпроцесса, который полностью завершится после истечения таймаута. –

+2

Небольшая коррекция (хотя этот ответ более года) Нитки не прерываются внутри улова и, наконец, блоки. Поэтому, предполагая хорошо написанный блок finally или использование блоков, приведенный выше пример не является проблемой. – Steve

-1

Использование Thread.Abort в порядке. Однако он не всегда прерывается немедленно. Если поток выполняет неуправляемый код, он фактически не прерывается, пока не вернется к управляемому коду.

1

Использование прерывания потока является достаточно безопасным. Однако, как упоминалось другими, прерывание потока не может быть прервано немедленно. Вызов прерывания потока приведет к возникновению исключения ThreadAbortException в потоке. Чтобы очистить ресурсы, вы можете поймать это исключение и выполнить необходимые очистки.

static void Run() 
{ 
    try 
    { 
    while(someCondition) 
    { 
     .... 
     .... 
     .... 
     if (someOtherCondition) 
      throw new ThreadAbortException("Thread aborted"); 
    } 
    } 
    catch(ThreadAbortException e) 
    { 
    ... 
    ... //clean up resources here. 
    ... 
    } 
    finally 
    { 
    ... 
    } 
} 
+0

Второе, что вы вводите ресурсы, которые нуждаются в очистке в вашем потоке, Thread.Abort * не * достаточно безопасен. –

+0

По-видимому, проблема в том, что Thread.Abort недостаточно умен, чтобы знать, что ваш код действительно может быть в блоке 'finally' и будет отменен прямо из этого блока. Если бы только он мог сказать и только прервать, если код не был в catch/finally, и дождаться, пока он не выйдет из блока ... – devios1

Смежные вопросы