Потоки в .NET: как перехватить прерывание в незапущенном потоке? - PullRequest
0 голосов
/ 03 января 2011

edit: кажется, что это является камнем преткновения, поэтому я просто уберу это с пути:

Я не использую это для синхронизации.Просто чтобы убить долго выполняющиеся задачи, когда они больше не становятся необходимыми / желательными.
Гипотетически : предположим, что эти потоки просто пишут в консоль (скажем: «Поток 1»), спят случайной длины изатем выйдите.Если они прерваны, я хочу, чтобы они сообщили мне с другой записью консоли (скажем: «Поток 1 прерван»).И я хотел бы иметь возможность перейти прямо к коду отмены, если я попытаюсь прервать его до того, как он будет запущен, без каких-либо шансов на выполнение его обычных функций.Если он прерван во время нормальной работы, он, конечно, напечатает оба.


У меня есть часть потоков, которые я хочу запустить по порядку, на сайте ASP, работающем .NET 2.0 с Visual Studio 2008 (нетПредставьте себе, насколько все это имеет значение, но это так), и они могут иметь прерванный код очистки, который следует запускать независимо от того, как далеко они справляются со своей задачей.Поэтому я создаю поток, подобный следующему:

Thread t = new Thread(delegate() {
   try { 
      /* do things */ 
      System.Diagnostics.Debug.WriteLine("try");
   }
   catch (ThreadAbortException) {
      /* cleanup */ 
      System.Diagnostics.Debug.WriteLine("catch");
   }
});

Теперь, если я хочу прервать набор потоков на полпути, очистка все еще может быть желательна в дальнейшем.Просмотр MSDN подразумевает, что вы можете .Abort () поток, который еще не запущен, а затем .Start () его, после чего он получит исключение и будет работать нормально.Или вы можете .Join () прервать поток, чтобы дождаться его завершения.Предположительно, вы можете объединить их.

http://msdn.microsoft.com/en-us/library/ty8d3wta(v=VS.80).aspx
Чтобы дождаться прерывания потока, вы можете вызвать метод Join в потоке после вызова метода Abort, но нет гарантии, чтоожидание закончится.
Если прерывание вызывается для потока, который не был запущен, поток прерывается при вызове запуска.Если прерывание вызывается в потоке, который заблокирован или находится в спящем режиме, поток прерывается, а затем прерывается.

Теперь, когда я отлаживаю и выполняю этот код:

t.Abort(); // ThreadState == Unstarted | AbortRequested
t.Start(); // throws ThreadStartException: "Thread failed to start."
// so I comment it out, and
t.Join(); // throws ThreadStateException: "Thread has not been started."

Ни в коем случае я не вижу никаких выходных данных, и при этом не достигаются никакие точки останова ни в блоке try, ни в catch.
Как ни странно, исключение ThreadStartException не указано как возможный бросок .Start (), отсюда: http://msdn.microsoft.com/en-us/library/a9fyxz7d(v=VS.80).aspx (или любая другая версия)

Я понимаю, что этого можно избежать, если иметь параметр start, который указывает, должен ли поток переходить к коду очистки, и предшествовать вызову Abort (что, вероятно, будетделать).И я мог бы .Start () поток, а затем .Abort () его.Но поскольку между .Start и .Abort может пройти неопределенное время, я считаю это ненадежным, и в документации, похоже, говорится, что мой оригинальный метод должен работать.

Я что-то упустил?Является ли документация неправильной?

edit: ow.И вы не можете вызвать .Start (param) в непараметризированном Thread (Start).Есть ли способ узнать, является ли поток параметризованным или нет, кроме проб и ошибок?Я вижу личный m_Delegate, но ничего публичного ...

Ответы [ 2 ]

3 голосов
/ 03 января 2011

При использовании ...

t.Abort();
t.Start();

... внутреннее исключение ThreadStartExcpetion будет содержать ThreadAbortExeption так же, как состояния msdn: ( если Abort вызывается в потоке, который не был запущенпоток будет прерван при вызове Start )

Если вы выполните ...

t.Start();
t.Abort();

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

Если вы тестируете что-то вроде ...

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

... код "очистки" всегда должен выполняться.

Если вам нужноЧтобы выполнить код очистки, даже если поток не начал ничего делать, возможное решение - запустить метод очистки вместе с вызовом Abort.

Более того, вам следует избегать прерывания потоков и использовать другие методы (http://msdn.microsoft.com/en-us/library/ms228964.aspx)

0 голосов
/ 03 января 2011

Я понимаю, что документация подразумевает для вас, но это не то, что происходит. Если вы прервете поток и затем запустите его, он никогда не будет выполнен никоим образом. CLR достаточно умен, чтобы знать, что прерывание потока - ненадежный бизнес, и поэтому нельзя упускать возможность вообще пропустить выполнение потока.

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

Имейте в виду, что понятие .net "очистки" после прерывания потока состоит в том, чтобы выгрузить домен приложения из сборок, которые выполняли прерванный поток. Это еще один способ сказать: «Не ожидайте, что это хорошо очистится». Сначала вы всегда должны искать дизайн, который не требует прерывания потоков.

...