Здравствуйте, Tom, Вы писали:
Tom>Если желание и понимание есть то сделать можно. Если понимания нет то проблемы с юзингом можно получить и без abort-а. Элементарный случай — исключение в конструкторе.
Можно подробнее?
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Tom, Вы писали:
Tom>>Если желание и понимание есть то сделать можно. Если понимания нет то проблемы с юзингом можно получить и без abort-а. Элементарный случай — исключение в конструкторе. S>Можно подробнее?
А что подробнее то?
Вот минимальный пример.
namespace ConsoleApplication1
{
public class Foo : IDisposable
{
public Foo()
{
// Imagine we have got resource here...
// And then calling something elsethrow new Exception("вай беда бедаё");
}
public void Dispose()
{
Console.WriteLine("Disposed");
}
}
class Program
{
static void Main(string[] args)
{
try
{
using (new Foo())
{
}
}
catch (Exception)
{
Console.WriteLine("catched");
}
}
}
}
Здравствуйте, Tom, Вы писали:
Tom>Здравствуйте, samius, Вы писали:
S>> S>>In short, Thread.Abort is at best indicative of bad design, possibly unreliable, and extremely dangerous. It should be avoided at all costs; the only time you should ever even consider aborting a thread is in some sort of "emergency shutdown" code where you are attempting to tear down an appdomain as cleanly as possible. Tom>Вы будете удивлены но я абсолютно с ним согласен. Что абсолютно не значит что ThreadAbort зло во всех случаях. Tom>Есть целый класс случаев когда без него просто невозможно обойтись.
А он и не пишет что зло во всех случаях. Он пишет "избегать любой ценой". Tom>Это случаи когда вы не владеете кодом который выполняется в вашем потоке в данную минуту.
Для меня это = практически всегда. Даже из файла прочитать не можем, не выполняя код, которым не владеем. Tom>Примеры ASP.NET, WCF, SQL Server & CLR. Tom>Во всех этих примерах применяется ThreadAbort
Да, я видел что в ASP.NET чуть ли не принято было звать Abort чуть ли не в каждом запросе. Я не одобряю эту практику.
Здравствуйте, Tom, Вы писали:
Tom>Здравствуйте, samius, Вы писали:
S>>Здравствуйте, Tom, Вы писали:
Tom>>>Если желание и понимание есть то сделать можно. Если понимания нет то проблемы с юзингом можно получить и без abort-а. Элементарный случай — исключение в конструкторе. S>>Можно подробнее? Tom>А что подробнее то? Tom>Вот минимальный пример.
Пардон, я не вижу в этом примере проблемы с юзингом. Я вижу проблему с пониманием конструкции юзинг.
Tom, если вкратце, то я понимаю, что в некоторых ситуациях может показаться, что Thread.Abort использовать можно. Да и вам лично никто не запретит Проблема в том, что гарантировать, что поток не использует каких-то разделяемых ресурсов, и что Thread.Abort() в таком случае не приведет к проблеме, очень проблематично. Вы будете проверять внутренности всех методов вызываемых потоком? Что они там внутри делают, не используется ли там внутри разделяемое состояние? Есть ли гарантии что программист при этом не ошибётся? Поэтому просто как rule of thumb считается, что Thread.Abort() использовать не нужно никогда. При этом да, при желании (или из принципа, чтобы доказать ) вы можете написать метод потока, который можно завершить с Thread.Abort() и ничего супер страшного не произойдет.
public sealed class ResourceWrapper : IDisposable
{
private readonly HandleWrapper _wrapper;
public ResourceWrapper()
{
_wrapper = new HandleWrapper {Handle = AcquireHandle()};
}
~ResourceWrapper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
// Финализатор может быть вызван для неполностью
// сконструированного объекта!!if (_wrapper.Handle != IntPtr.Zero)
{
ReleaseHandle(_wrapper.Handle);
}
}
private static IntPtr AcquireHandle()
{
return IntPtr.Zero;
}
private static void ReleaseHandle(IntPtr handle)
{
// Do something to release handle!
}
struct HandleWrapper
{
public IntPtr Handle;
}
}
Давай внимательно на него посмотрим и ответим на вопрос, является ли класс ResourceWrapper безопасным с точки зрения исключений?
Да, есть три гарантии безопасности исключений по Абрамсу: базовая, строгая и гарантия отсутствия исключений.
С первого взгляда кажется, что этот класс обеспечивает базовую гарантию исключений и утечки ресурсов здесь невозможны. И это действительно так и есть, если говорить об обычных исключениях. Но в CLR (и в CLI) помимо синхронных, есть еще несколько специальных асинхронных исключений, которые могут быть сгенерированы CLR практически в любой точке программы. К таким исключениям относятся: StackOverflowException, OutOfMemoryException и ThreadAbortException.
Теперь, если посмотреть, что я не стал создавать конструктор для вложенной структуры HandleWrapper, то станет понятно, что против асинхронных исключений, данный код не является безопасным!
Поскольку ThreadAbortException может возникнуть практически в любой точке приложения, кроме блока finally, unmanaged коде и Critical Excecution Region-ах, то без изменений, данный код будет небезопасным.
Безопасность исключений, это как и безопасность вообще, если есть хотя бы один небезопасный класс, то и все классы, которые его используют становятся небезопасными с точки зрения исключений. Поэтому если я предоставлю в качестве библиотеки класс ResourceWrapper, хорошо проверенный и протестированный, то все ваше приложение будет небезопасным с точки зрения асинхронных исключений, если оно будет использовать этот класс в виде поля класса или переменной внутри метода.
Ок, это какой-то хардкор, но можем рассмотреть и более простой пример:
static void UseFile(string filename, int position)
{
using(var file = new FileStream(filename, FileMode.Open) {Position = position})
{ }
}
Ок, это тоже пример надуманный? вполне возможно, но всегда когда захват происходит не атомарно, то код перестает быть безопасным с точки зрения асинхронных исключений!
Проблема асинхронных исключений вообще и ThreadAbortException в частности, что мы не можем знать заранее, является ли исполняемый некоторым потоком код безопасным с точки зрения асинхронных исключений или нет. Этот код может успешно работать много лет и падать один раз в миллион вызовов. И тут дело не в детях и зажигалках, а в том, что мы не можем гарантировать, что наше приложение будет нормально работать при наличии асинхронных исключений, когда сам .NET Framework не гарантирует нормальную работу в этих условиях.
Вот и получается, что единственным безопасным вариантом вызова Thread.Abort является прекращение работы текущего потока, а обрыв другого потока всегда сопряжен с определенным риском, не зависимо от того, насколько вы доверяете себе и своему коду.
P.S. Достаточно погуглить на предмет количества различных утечек ресурсов (в частности файлов) при наличии Thread.Abort. Самый распространенные фиксятся, но я не думаю, что когда либо в ближайшем будущем .NET Framework станет безопасным с точки зрения асинхронных исключений;0
Дело в том, что всё не так просто. Начните с того, что посмотрите сколько разных файлов с названием System.Core.dll имеется в наличии у Вашей системы... И где они расположены...
>Передавайте привет декомпилерам, они такие классные, особенно бесплатные.
Привет не 21-летним сеньерам
А>Там не NUMA, там мало памяти (всего 16 Гб).
Объём не имеет никакого отношения к вопросу. Если в системе стоит два Xeon E5-2600, то обратиться к памяти соседа процессор может только через QPI-линк с ним. В отличии от своей собственной, с которой он соединён напрямую непосредственно контроллером памяти.
А>Рихтер предлагает свою библиотеку, она не рабочая.
Как ? И Рихтер тоже ?
Re[8]: ReaderWriterLockSlim problems
От:
Аноним
Дата:
16.12.13 19:33
Оценка:
Здравствуйте, SergeyT., Вы писали:
ST>Проблема асинхронных исключений вообще и ThreadAbortException в частности, что мы не можем знать заранее, является ли исполняемый некоторым потоком код безопасным с точки зрения асинхронных исключений или нет. Этот код может успешно работать много лет и падать один раз в миллион вызовов. И тут дело не в детях и зажигалках, а в том, что мы не можем гарантировать, что наше приложение будет нормально работать при наличии асинхронных исключений, когда сам .NET Framework не гарантирует нормальную работу в этих условиях.
А в каких-каких местах он не гарантирует? Можно два-три примера, а то аж страшно представить что все сайты на ASP.NET — не нормально работающие приложения, ругулярно впрыскивающие в чужой код TBA.
Re[4]: ReaderWriterLockSlim problems
От:
Аноним
Дата:
16.12.13 20:11
Оценка:
Здравствуйте, drol, Вы писали:
D>Здравствуйте, Аноним, Вы писали:
А>>В каком здесь месте нарисовался Volatile.Write?
D>То есть с инкрементом owners Вы разобрались. Я Вас правильно понял ?
D>Теперь об ExitMyLock():
D>
D>Дело в том, что всё не так просто. Начните с того, что посмотрите сколько разных файлов с названием System.Core.dll имеется в наличии у Вашей системы... И где они расположены...
Начну с того, что я привел код из памяти проблемной программы. На этом заканчиваю. Дальше не отвечаю, убеждать что проблема на твоем фреймворке и домашнем ПэКа отсутствует меня не нужно. Спасибо.
Так что, для начала, я рекомендую Вам взять назад Ваши слова о декомпиляторах.
А>На этом заканчиваю.
А сколько понтов было в Вашем первом посте...
А>Дальше не отвечаю, убеждать что проблема на твоем фреймворке и домашнем ПэКа отсутствует меня не нужно.
Вы разговариваете сам с собой. Я не знаю существует проблема или нет. Я показываю, что Ваш анализ является поверхностным и бестолковым.
ST>Ок, давай сделаем небольшую перезагрузку
ST>Рассмотрим такой код:
Я бы такой код назвал конечно наивной реализацией.
В приличных домах принято использовать PrepareConstrainedRegions()
По поводу /// using(var file = new FileStream
По сути проблема тут в самом Disposable паттерне.
В идеале в нём должен быть ещё один метод — метод аллокации ресурса,
тогда все вопросы с конструктором и соответственно присвоением переменной отпали бы.
Хотя и сейчас можно переписать компилятор и если присвоение делается в блоке юзинг то вначале присваивать результат переменной а уж потом вызывать конструктор.
ST>P.S. Достаточно погуглить на предмет количества различных утечек ресурсов (в частности файлов) при наличии Thread.Abort. Самый распространенные фиксятся, но я не думаю, что когда либо в ближайшем будущем .NET Framework станет безопасным с точки зрения асинхронных исключений;0
Он уже безопасен с некоторыми оговорками. Иначе его бы никогда не впихнули в сиквел.
Забыл совсем сказать, когда бойцы прикручивали CLR к сиквелу — они изобрели HostProtectionAttribute у которого есть MayLeakOnAbort.
Если уже совсем страшно — то можно ориентироваться по нему.
Здравствуйте, Tom, Вы писали:
Tom>Проблемы с ThreadAbort у людей бывают когда они не понимают что это такое, когда выбрасывается и что с ним вообще делать надо.
Тут уже за меня ответили, причём в основном — гораздо лучше, чем я смогу.
Если суммировать: есть такая штука как bad practices. Их использование в 99.(9)% случаев означает, что у вас _уже_ возникла проблема на предыдущем шаге, но вместо решения самой проблемы вы пытаетесь подпереть её костылём. Ну, как заклеивать лампочку "проверьте двигатель" изолентой, чтоб не мешала. Исключения всегда бывают, но в основном хвастаться смотри ма, без рук "люди не понимают, а я могу" — это чистой воды ребячество.
И да, thread.Abort() — это bad practices в чистейшем дистиллированном виде.
Не, серьёзно — вы правда хотите протащить в продакшн проблемы, которые не воспроизводятся стабильно под отладкой?
Здравствуйте, Tom, Вы писали:
Tom>Кстате твой пример с FileStream безопасен более чем
Этот код безопасен с точки зрения синхронных исключений (при учете, что setter свойства Position никтогда не бросает исключений), но с точки зрения асинхронных исключений?
static void UseFile(string filename, int position)
{
var tmp = new FileStream(filename, FileMode.Open);
var tmp.Position = position; // тут может упасть ThreadAbortusing (var file = tmp) {}
}
В результате мы не потечем, но постусловие метода UseFile выполнено не будет, что может привести к каскаду проблем далее по коду.
З.Ы. ИМХО, использовать или не использовать Thread.Abort в своем коде — выбор каждого. Если ты считаешь, что потенциальные проблемы (данное обсуждение является примером того, что они возможны) не беспокоят — тогда ОК, вопрос в другом, если это именно твой код, то чем не устроили другие альтернативы? Если же это инфраструктура и выбора нет, то тут, собственно и обсуждать нечего.
ST>Этот код безопасен с точки зрения синхронных исключений (при учете, что setter свойства Position никтогда не бросает исключений), но с точки зрения асинхронных исключений?
И и сточки зрения асинхронных он тоже безопасен.
Смысл в том что внутрях при вызове native функций используется SafeHandle по этому в принипе пофиг если исключение будет выкинуто в лдюбом месте.
ST>З.Ы. ИМХО, использовать или не использовать Thread.Abort в своем коде — выбор каждого. Если ты считаешь, что потенциальные проблемы (данное обсуждение является примером того, что они возможны) не беспокоят — тогда ОК
Я тебе про то что вероятность проблем очень сильно преувеличена и что уже давным давно придумали способы борьбы с асинхронными ислючениями в виде CER&Finally блока
S>И да, thread.Abort() — это bad practices в чистейшем дистиллированном виде.
Передай это разработчикам сиквела, WCF и IIS-а а то они не вкурсе
Народная мудрось
всем все никому ничего(с).
Re[5]: ReaderWriterLockSlim problems
От:
Аноним
Дата:
17.12.13 10:39
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, drol, Вы писали:
D>>Здравствуйте, Аноним, Вы писали:
А>>>В каком здесь месте нарисовался Volatile.Write?
D>>То есть с инкрементом owners Вы разобрались. Я Вас правильно понял ?
D>>Теперь об ExitMyLock():
D>>
D>>Дело в том, что всё не так просто. Начните с того, что посмотрите сколько разных файлов с названием System.Core.dll имеется в наличии у Вашей системы... И где они расположены...
А>Начну с того, что я привел код из памяти проблемной программы. На этом заканчиваю. Дальше не отвечаю, убеждать что проблема на твоем фреймворке и домашнем ПэКа отсутствует меня не нужно. Спасибо.
не обращай на него внимание это местный тролль. вместо конструктива ему постоянно необходимо все преподнести на блюдечке, при этом в каждом 3-м сообщении скрытый пафос и попытки унизить всех и вся.
да и в теме не силен, часто пишет всякую херь типа
V>Да. Но volatile — это не синхронизация доступа. Это только указание компилятору не кэшировать обращения к переменой.
Это неправда. Операции над volatile-полями включают в себя acquire\release семантику. Посему на них вполне можно делать массу разновидностей синхронизации. Только понимать надо что к чему когда и где...
при этом понятия не имеет что такое acquire\release
Здравствуйте, Tom, Вы писали:
Tom>Передай это разработчикам сиквела, WCF и IIS-а а то они не вкурсе
Это очень рискованное заявление
Конкретно про ms sql я могу и поспорить, т.к. лет семь назад копался в нюансах реализации hosted clr. Если коротко, по памяти и не совсем корректно (как всегда есть нюансы): при разработке под ms sql нужно соблюдать ряд ограничений, в частности — недопустимо использование разделяемого состояния/static-полей. В том числе и по причине возможного thread.Abort() (хотя там не совсем классический .Abort()).
В принципе, можно на рекомендации наплевать, тогда придётся или плодить сer (бонусом — лаги и невозможность использование untrusted сборок), или бороться с битым состоянием для отдельных запросов (сессий). Оно конечно лечится через выгрузку sqlclr appdomain, но всё равно неприятно.
Про wcf/iis — очень интересно. Где там используется thread.Abort()? Appdomain recycling не считается по вполне понятным причинам