Вызывающий поток. Аварийное прекращение работы на потоке от ThreadPool

Мой коллега пользуется сторонней библиотекой.NET, для которой у нас нет исходного кода. Мы используем ThreadPool, чтобы иметь много вызова потоков в эту библиотеку, и иногда один из потоков будет просто зависать навсегда, в то время как остальная часть их весело двигается с пыхтением вперед.

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

static Dictionary<Thread, DateTime> started = new Dictionary<Thread, DateTime>();

static void DoSomeWork(object foo)
{
    lock(started)
        started[Thread.CurrentThread] = DateTime.Now;

    SomeBuggyLibraryThatMightInfiniteLoopOrSomething.callSomeFunction(doo);

    lock(started)
        started.Remove(Thread.CurrentThread);
}

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

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

Таким образом, то, что я хочу знать, является этим: учитывая, что мы будем звонить Thread.Abort на потоке, который принадлежит ThreadPool, там какие-либо специальные проблемы, вызванные этими являющимися потоками ThreadPool, и мы должны вручную вращать новый поток для замены того, который был уничтожен, или ThreadPool сделает это для нас?

18
задан Eli Courtwright 25 February 2010 в 18:45
поделиться

5 ответов

Java не имеет пространств имен, имеет пакеты. И да, классы без объявлений пакетов неявно являются частью « неименованного пакета », часто называемого также «пакетом по умолчанию». Однако, поскольку импорт классов из безымянного пакета невозможен и поскольку языковая спецификация явно позволяет реализациям иметь разные правила относительно того, видны ли классы в безымянных пакетах друг другу и каким образом, обычно рекомендуется помещать все классы в именованные пакеты, за исключением экспериментального кода.

-121--2145738-

Вы можете попробовать сделать блокировку с/ LOCK_EX - и если блокировка не работает, это означает, что она все еще записывается. Вращайтесь так, пока не получите замок, и ослепление должно быть сделано. Это приведет к сбою, если Dazzle когда-либо закроет файл и снова откроет его в режиме добавления, поэтому это не лучшее решение.

-121--4859309-

Нет, не следует вызывать функцию Abort on threads в пуле потоков. Из моего локального тестирования кажется, что ThreadPool воссоздает потоки, если прервать их - я прервал 1000 потоков пула потоков, и он все еще работал. Я не знаю, стоит ли тебе полагаться на это поведение, но, возможно, в этом случае тебе это сойдет с рук. В целом, хотя использование Thread.Abort не является правильным способом для этого.

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

9
ответ дан 30 November 2019 в 08:43
поделиться

Чтобы прояснить то, что говорит Марк, если вы вызываете Thread.Abort, вы понятия не имеете, где он прервется в стороннем компоненте из-за особого характера ThreadAbortException - он может оставить открытым, например, FileStream.

Я бы лично создавал потоки сам, ссылаясь на IList или Queue (поскольку ThreadPool больше подходит для fire and forgets или WaitHandles), и в зависимости от того, считаете ли вы, что прерывание потока, использующего сторонний компонент, не так опасно, Abort его.

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

В качестве альтернативы

Чтобы придерживаться использования ThreadPool, вы можете использовать этот Smart Thread Pool.

3
ответ дан 30 November 2019 в 08:43
поделиться

У вас есть другой вариант (который я бы принял, если бы у меня был свободный день):

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

1
ответ дан 30 November 2019 в 08:43
поделиться

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

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

Я советую вам выяснить, где этот код зависает (трассировка стека ThreadAbortException должна дать вам много информации). Если он всегда зависает на одном и том же месте (вероятно, это тупик), выясните с помощью Reflector, не приведет ли прерывание потока в этой точке к повреждению состояния. С этой информацией вы, возможно, уже сможете решить проблему (возможно, вы заблокируете объект этой библиотеки) или можете послать письмо автору этой библиотеки. Если все это не поможет, и вы увидите, что прерывание не представляет опасности, будьте прагматичны и убейте ее :-)

Однако, если есть изменение какого-либо повреждения состояния, вы должны попытаться следовать ответу Марка Байерса. То есть: попробуйте запустить эту библиотеку в собственном AppDomain. Таким образом, вы сможете выгрузить весь AppDomain, и никакие изменения в нем не повлияют на ваше приложение.

7
ответ дан 30 November 2019 в 08:43
поделиться

Прочтите 'Abortable Thread Pool' Стивена Туба. Он предоставляет исходный код для прерываемого пула потоков. Это интересное чтение.

Он вызывает свой собственный обратный вызов HandleItem при постановке пула потоков в очередь. Затем внутри «HandleItem» он выполняет реальный обратный вызов после добавления текущего потока в список словарей внутри своего класса-оболочки.

ThreadPool.QueueUserWorkItem(new WaitCallback(HandleItem));

HandleItem(...) {
...
_threads.Add(item, Thread.CurrentThread);
...
}

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

Dictionary<WorkItem, Thread>() _threads = New Dictionary<WorkItem, Thread>();

http://msdn.microsoft.com/en-us/magazine/cc163644.aspx

3
ответ дан 30 November 2019 в 08:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: