виснет на Thread.Abort()
От: UberPsychoSvin  
Дата: 15.04.14 04:57
Оценка:
Зависло на Thread.Abort().

Есть такой участок кода.
foreach (var thread in Threads)
{
    try
    {
        Log.Warn("aborting thread : " + thread.Name);
        thread.Abort();
    }
    catch (Exception ex)
    {
        Log.Error("thread aborting failed", ex);
    }
}

Зависло после Log.Warn("aborting thread : " + thread.Name); ему просто негде больше зависнуть, кроме как на thread.Abort();. Вот какого хрена?
Re: виснет на Thread.Abort()
От: Sinix  
Дата: 15.04.14 05:33
Оценка: 12 (1) +4
Здравствуйте, UberPsychoSvin, Вы писали:

UPS>Зависло после Log.Warn("aborting thread : " + thread.Name); ему просто негде больше зависнуть, кроме как на thread.Abort();. Вот какого хрена?


А инструкцию читать не пробовали?

The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region. If the thread that calls Abort holds a lock that the aborted thread requires, a deadlock can occur.

(c)

Кучу раз ведь обсуждалось: единственный способ не огрести проблем с thread.Abort() — не использовать его вообще.

P.S. "ему просто негде больше зависнуть" проверяется подключением отладчика и проверкой стека "зависших" потоков. Неоднократно наблюдал (да и сам участвовал) цепочку "да нечему там падать!" -> "как мы раньше не заметили???".
Re[2]: виснет на Thread.Abort()
От: UberPsychoSvin  
Дата: 15.04.14 07:09
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, UberPsychoSvin, Вы писали:


UPS>>Зависло после Log.Warn("aborting thread : " + thread.Name); ему просто негде больше зависнуть, кроме как на thread.Abort();. Вот какого хрена?


S>А инструкцию читать не пробовали?

S>

S>The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region. If the thread that calls Abort holds a lock that the aborted thread requires, a deadlock can occur.

S>(c)

S>Кучу раз ведь обсуждалось: единственный способ не огрести проблем с thread.Abort() — не использовать его вообще.


S>P.S. "ему просто негде больше зависнуть" проверяется подключением отладчика и проверкой стека "зависших" потоков. Неоднократно наблюдал (да и сам участвовал) цепочку "да нечему там падать!" -> "как мы раньше не заметили???".

Эммм, ну вообще да, у меня там у каждого треда в finally{} локи которые отпускаются только после всех Thread.Abort().
Но экспериментик показал что всё норм и я успокоился, а оно оказывается и так и сяк может.

private static void Body()
{
    try
    {
        for (; ; ) {}
    }
    finally 
    {
        lock (Lock)
        {
            for (;;)
            {
            Console.WriteLine("->");
            }
        }
    }
}


Такой вопрос, а чем килять треды, если не Thread.Abort().
Re[3]: виснет на Thread.Abort()
От: Sinix  
Дата: 15.04.14 07:42
Оценка: +2
Здравствуйте, UberPsychoSvin, Вы писали:

UPS>Такой вопрос, а чем килять треды, если не Thread.Abort().

Ничем. В общем случае (т.е. если вы специально не затачивали весь код под прерывание потоков) после Thread.Abort состояние программы можно рассматривать как повреждённое: где-то "завис" флаг или блокировка, где-то — не отписались от события, там валяется открытый файл или соединение, тут — недоинициализированный объект...

Используйте таски вместе с CancellationToken и не мучайтесь.
Re[4]: виснет на Thread.Abort()
От: UberPsychoSvin  
Дата: 15.04.14 08:20
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, UberPsychoSvin, Вы писали:


UPS>>Такой вопрос, а чем килять треды, если не Thread.Abort().

S>Ничем. В общем случае (т.е. если вы специально не затачивали весь код под прерывание потоков) после Thread.Abort состояние программы можно рассматривать как повреждённое: где-то "завис" флаг или блокировка, где-то — не отписались от события, там валяется открытый файл или соединение, тут — недоинициализированный объект...

S>Используйте таски вместе с CancellationToken и не мучайтесь.

Я и так использую такой подход у себя, но виснет чужое апи. А оно сделано так что там совсем ничего не кэнселится.
Re[5]: виснет на Thread.Abort()
От: Sinix  
Дата: 15.04.14 08:28
Оценка:
Здравствуйте, UberPsychoSvin, Вы писали:

S>>Используйте таски вместе с CancellationToken и не мучайтесь.

UPS>Я и так использую такой подход у себя, но виснет чужое апи. А оно сделано так что там совсем ничего не кэнселится.

Надавать по ушам автору или заменить код. Других вариантов, увы, не предусмотрено

Если других вариантов нет:
* можно запускать "подозрительный" код в отдельном домене и в случае чего убивать домен целиком.
* можно просмотреть глючный код через ilspy/dotpeek и убедиться, что код не имеет разделяемого состояния. Если повезло, то в принципе можно убивать поток. Если не повезло — см предыдущий пункт. Проверку кода придётся повторять после каждого обновления библиотеки.
Re[6]: виснет на Thread.Abort()
От: UberPsychoSvin  
Дата: 15.04.14 08:38
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, UberPsychoSvin, Вы писали:


S>>>Используйте таски вместе с CancellationToken и не мучайтесь.

UPS>>Я и так использую такой подход у себя, но виснет чужое апи. А оно сделано так что там совсем ничего не кэнселится.

S>Надавать по ушам автору или заменить код. Других вариантов, увы, не предусмотрено

Я ни разу такого апи не видел что бы всё жадное по времени кэнселилось. Может в будущем это и станет реальностью.

S>Если других вариантов нет:

S>* можно запускать "подозрительный" код в отдельном домене и в случае чего убивать домен целиком.
Я вызываю ThreadAbortException что бы у меня при стопе сервиса отработали все финализаторы. Убивать целиком смысла не вижу. Уж проще выкинуть все ThreadAbort и позволить винде убить процесс.

Наверно я перестрою логику так, что бы у меня ничего не дедлочилось, и буду по прежнему абортить зависшие треды.
Re[7]: виснет на Thread.Abort()
От: Sinix  
Дата: 15.04.14 08:47
Оценка:
Здравствуйте, UberPsychoSvin, Вы писали:

UPS>Я вызываю ThreadAbortException что бы у меня при стопе сервиса отработали все финализаторы.


Для этого Thread.Abort() нафиг не нужен. Наоборот, он может способствовать утечке ресурсов (хотя для этого надо постараться):
SomeClass.SomeStaticField = myResource
// ... 
// <- Прилетает ThreadAbortException, ресурс утёк;)
SomeClass.SomeStaticField = null;


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

Ну... удачи
Re[8]: виснет на Thread.Abort()
От: Danchik Украина  
Дата: 15.04.14 10:19
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, UberPsychoSvin, Вы писали:


UPS>>Я вызываю ThreadAbortException что бы у меня при стопе сервиса отработали все финализаторы.


S>Для этого Thread.Abort() нафиг не нужен. Наоборот, он может способствовать утечке ресурсов (хотя для этого надо постараться):

S>
S>SomeClass.SomeStaticField = myResource
S>// ... 
S>// <- Прилетает ThreadAbortException, ресурс утёк;)
S>SomeClass.SomeStaticField = null;
S>


try finally никто не отменял. И я их пишу, так как exceptions тоже никуда не делись.

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

S>Ну... удачи

Согласен, от проблем он не избавиться. Отдельные процессы было бы понадежней.
Re[8]: виснет на Thread.Abort()
От: UberPsychoSvin  
Дата: 15.04.14 12:31
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, UberPsychoSvin, Вы писали:


UPS>>Я вызываю ThreadAbortException что бы у меня при стопе сервиса отработали все финализаторы.


S>Для этого Thread.Abort() нафиг не нужен. Наоборот, он может способствовать утечке ресурсов (хотя для этого надо постараться):

S>
S>SomeClass.SomeStaticField = myResource
S>// ... 
S>// <- Прилетает ThreadAbortException, ресурс утёк;)
S>SomeClass.SomeStaticField = null;
S>


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

S>Ну... удачи

Вот конкретика. У нас виндовый сервис. Нам нужно обработать его остановку.

1. Я устанавливаю кэнселейшен флаги
2. Жду таймаут.
3. Если есть висящие треды, вызываю им аборт.



try
{
    //чего то там делаем
    //потенциально_зависшее_место
    //чего то там делаем
    //чего то там делаем
    //чего то там делаем
}
finally
{
    //делаем чего то критичное, что надо по любому сделать.
}


из всех потенциально_зависшее_место, кидается эксцепшен, все треды им проносит, и отрабатывают все нужные финализаторы.

Вынести каждое потенциально_зависшее_место в отдельный сервис или в обёртку в AppDomain конечно можно, но это стрельба из пушки по воробьям. )

Есть какие-нибудь ещё подходы, что бы без Thread.Abort() ?
Re[9]: виснет на Thread.Abort()
От: Sinix  
Дата: 15.04.14 13:14
Оценка:
Здравствуйте, UberPsychoSvin, Вы писали:

UPS>Есть какие-нибудь ещё подходы, что бы без Thread.Abort() ?


Ну блин С "У нас виндовый сервис. Нам нужно обработать его остановку." и надо было начинать. Сценарий редкий: вам не важно состояние потоков после Abort(), система всё равно всё прибьёт.

Thread.Abort + убедиться, что остальной код не завязан на блокировки с зависающими потоками (вы и сами уже нашли этот момент) — что тут ещё думать-то?
Re[6]: виснет на Thread.Abort()
От: abibok  
Дата: 15.04.14 16:52
Оценка:
S>* можно запускать "подозрительный" код в отдельном домене и в случае чего убивать домен целиком.

Не поможет, там та же самая проблема, что и с Thread.Abort.
Единственный известный мне выход — запускать такой код в отдельном процессе.
Re[7]: виснет на Thread.Abort()
От: Sinix  
Дата: 16.04.14 04:55
Оценка:
Здравствуйте, abibok, Вы писали:


S>>* можно запускать "подозрительный" код в отдельном домене и в случае чего убивать домен целиком.

A>Не поможет, там та же самая проблема, что и с Thread.Abort.
В смысле?

Все ресурсы освободятся (если к ним есть финалайзеры, конечно). Разделяемого состояния между доменами обычно или нет вообще, или оно управляется хост-доменом. Native-код пока не рассматриваем. Что ещё может поломать состояние так, чтобы от этого не спасла выгрузка домена?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.