Re[7]: ReaderWriterLockSlim problems
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 16.12.13 18:06
Оценка: 159 (8)
Здравствуйте, Tom, Вы писали:

Ок, давай сделаем небольшую перезагрузку

Рассмотрим такой код:

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
Re[5]: ReaderWriterLockSlim problems
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 16.12.13 14:01
Оценка: 17 (2) +3
Здравствуйте, Tom, Вы писали:

S>>>>Автор создал себе офигенные проблемы уже в момент использования thread.Abort(), всё остальное — уже последствия. Расписывать подробно особого смысла нет, достаточно

Tom>>>Ээээ на этом месте по подробнее можно?

S>>Thread.Abort() — это метод отчаяния. Точно так же, как catch {}, он не решает исходную проблему, а маскирует её.

Tom>Это с кокого такого перепугу такое делается заявление?
Tom>Отчаяние это TerminateThread а Thread.Abort это более чем кошерное решение проблемы с закрытием и освобождение ресурсов.

Разница меджу TerminateThread и Thread.Abort в том, что первый гарантированно приведет к проблемам, а второй — лишь в некоторых случаях.

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

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


Tom>Или другой случай, случился ресайклинг у IIS App Pool-а, опять же что делать с зависшими запросами....

Когда мы точно знаем, что за код исполняется потоком, то все ОК, но в *общем случае* гарантировать корректное состояние программы после Thread.Abort нельзя.
Re[3]: ReaderWriterLockSlim problems
От: MozgC США http://nightcoder.livejournal.com
Дата: 16.12.13 16:21
Оценка: +5
Tom, если вкратце, то я понимаю, что в некоторых ситуациях может показаться, что Thread.Abort использовать можно. Да и вам лично никто не запретит Проблема в том, что гарантировать, что поток не использует каких-то разделяемых ресурсов, и что Thread.Abort() в таком случае не приведет к проблеме, очень проблематично. Вы будете проверять внутренности всех методов вызываемых потоком? Что они там внутри делают, не используется ли там внутри разделяемое состояние? Есть ли гарантии что программист при этом не ошибётся? Поэтому просто как rule of thumb считается, что Thread.Abort() использовать не нужно никогда. При этом да, при желании (или из принципа, чтобы доказать ) вы можете написать метод потока, который можно завершить с Thread.Abort() и ничего супер страшного не произойдет.
Re[5]: ReaderWriterLockSlim problems
От: Sinix  
Дата: 16.12.13 13:48
Оценка: 71 (4)
Здравствуйте, Tom, Вы писали:

Tom>Это с кокого такого перепугу такое делается заявление?

Ок, а как ещё назвать решение прерывать поток выполнения в произвольном месте?

Tom>Отчаяние это TerminateThread а Thread.Abort это более чем кошерное решение проблемы с закрытием и освобождение ресурсов.

Как раз с "кошерным" освобождением ресурсов _в общем случае_ у Thread.Abort большие проблемы. Первые же ссылки из гугла
http://stackoverflow.com/questions/710070/timeout-pattern-how-bad-is-thread-abort-really
http://joeduffyblog.com/2009/03/13/managed-code-and-asynchronous-exception-hardening/
http://stackoverflow.com/questions/6382997/is-using-thread-abort-and-handling-threadabortexception-in-net-safe-practice
http://geekswithblogs.net/akraus1/archive/2012/10/22/151047.aspx
http://onoffswitch.net/when-to-abort-a-thread/

Tom>Например: Случился таймаут выполнения метода WCF. Вопрос, что делать.

Tom>Оставлсять всё так как и есть, т.е. продолжить методу висесть или попытаться его заабортить...?
Во-первых, поток не является единицей изоляции. Прибивать надо AppDomain/хост-процесс.
Во-вторых, в твоих сценариях не предполагается продолжение работы остальных (зависящих от текущего) потоков. У автора исходной статьи такая надежда была
Ну, и в-третьих, твои сценарии предполагают чистые (утилитарные) потоки без разделяемого состояния. ReaderWriterLockSlim намекает на полностью противоположное.
Re[6]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 16.12.13 14:19
Оценка: -4
Здравствуйте, Sinix, Вы писали:

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


Tom>>Это с кокого такого перепугу такое делается заявление?

S>Ок, а как ещё назвать решение прерывать поток выполнения в произвольном месте?
Как угодно. Если это операция безопасна то не вижу проблем. С ThreadAbort и нормальными руками это вполне безопасно.

Tom>>Отчаяние это TerminateThread а Thread.Abort это более чем кошерное решение проблемы с закрытием и освобождение ресурсов.

S>Как раз с "кошерным" освобождением ресурсов _в общем случае_ у Thread.Abort большие проблемы. Первые же ссылки из гугла
Это конечно круто взять ссылки из гугла и кинуть их сюда.
Это конечно же доказывает многое...
Проблемы с ThreadAbort у людей бывают когда они не понимают что это такое, когда выбрасывается и что с ним вообще делать надо.
Это мне напоминает мнение когда люди считают проблемой — любое исключение не понимая что исключение это просто механизм, инструмент в их руках.
Причём этим инструментом можно себе дырку в ноге прокалупать или можно построить что то хорошее...

Tom>>Например: Случился таймаут выполнения метода WCF. Вопрос, что делать.

Tom>>Оставлсять всё так как и есть, т.е. продолжить методу висесть или попытаться его заабортить...?
S>Во-первых, поток не является единицей изоляции. Прибивать надо AppDomain/хост-процесс.
Очень интересно. Т.е. если у меня таймаут при вызове веб сервиса мне надо домен прибить?
Или ещё круче аж процесс? Может проще винду перегрузить или даже диск отформатировать...

S>Во-вторых, в твоих сценариях не предполагается продолжение работы остальных (зависящих от текущего) потоков. У автора исходной статьи такая надежда была

S>Ну, и в-третьих, твои сценарии предполагают чистые (утилитарные) потоки без разделяемого состояния.
Ээээ, опять же с какого перепугу???
Народная мудрось
всем все никому ничего(с).
Re[5]: ReaderWriterLockSlim problems
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.12.13 13:39
Оценка: 22 (1) +2
Здравствуйте, Tom, Вы писали:

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


Tom>А что код фрефмворка обязан вызывать Thread.Abort что бы заабортить поток?

Не знаю, что код фреймворка вызывает что бы заабортить поток, но вот мнение Липперта относительно Abort-а

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.

и еще

>Are there any other posibility to terminate threads?

Yes. Your problem is that you should never start up a thread that you cannot tell politely to stop, and it stops in a timely manner. If you are in a situation where you have to start up a thread that might be (1) hard to stop, (2) buggy, or worst of all (3) hostile to the user, then the right thing to do is to make a new process, start the thread in the new process, and then terminate the process when you want the thread to go down. The only thing that can guarantee safe termination of an uncooperative thread is the operating system taking down its entire process.

Полагаю что все-таки фреймворк не так часто абортит потоки, как вам хочется.
Re[4]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 16.12.13 12:59
Оценка: -3
Здравствуйте, Sinix, Вы писали:

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


S>>>Автор создал себе офигенные проблемы уже в момент использования thread.Abort(), всё остальное — уже последствия. Расписывать подробно особого смысла нет, достаточно

Tom>>Ээээ на этом месте по подробнее можно?

S>Thread.Abort() — это метод отчаяния. Точно так же, как catch {}, он не решает исходную проблему, а маскирует её.

Это с кокого такого перепугу такое делается заявление?
Отчаяние это TerminateThread а Thread.Abort это более чем кошерное решение проблемы с закрытием и освобождение ресурсов.

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

А с чего ты взял что ты вообще поток контролировал.
Представь себя на месте II&ASP.NET или того же WCF.
Например: Случился таймаут выполнения метода WCF. Вопрос, что делать.
Оставлсять всё так как и есть, т.е. продолжить методу висесть или попытаться его заабортить...?

Или другой случай, случился ресайклинг у IIS App Pool-а, опять же что делать с зависшими запросами....
Народная мудрось
всем все никому ничего(с).
Re[7]: ReaderWriterLockSlim problems
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.12.13 14:38
Оценка: +3
Здравствуйте, 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 чуть ли не в каждом запросе. Я не одобряю эту практику.
Re[3]: ReaderWriterLockSlim problems
От: samius Япония http://sams-tricks.blogspot.com
Дата: 15.12.13 15:44
Оценка: 6 (1) +1
Здравствуйте, Tom, Вы писали:

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


S>>Автор создал себе офигенные проблемы уже в момент использования thread.Abort(), всё остальное — уже последствия. Расписывать подробно особого смысла нет, достаточно

Tom>Ээээ на этом месте по подробнее можно?
Tom>thread.Abort используется в куче мест самим фрейсворком.
Я бы не сказал что в куче

Thread.Abort used by
   System.Media.SoundPlayer.LoadSync()
   System.Media.SoundPlayer.SetupSoundLocation(string)
   System.Media.SoundPlayer.SetupStream(Stream)
   System.ServiceModel.ComIntegration.DllHostInitializeWorker.Startup(IProcessInitControl)
Thread.Abort(object) used by
   System.Web.HttpResponse.AbortCurrentThread()
   System.Web.RequestTimeoutManager.RequestTimeoutEntry.TimeoutIfNeeded(DateTime)

Возможно куча пролетела мимо, но в рефлекторе на момент анализа было порядка 20и сборок фреймворка.
Re[9]: ReaderWriterLockSlim problems
От: Sinix  
Дата: 18.12.13 06:27
Оценка: 3 (1) +1
Здравствуйте, Serginio1, Вы писали:

S>но если я помечу атрибутом Cer.Success то таких проблем быть не должно?


Неа, это просто способ документировать контракт вашего метода по обработке неожиданных исключений.

Там нет никакой магии и сам по себе метод "безопасным" не станет. Msdn:

The ReliabilityContractAttribute attribute provides a mechanism for you to document your code, and to indicate what type of reliability guarantees you can make in the face of exceptional conditions that could potentially lead to an inconsistent state. In this context, exceptional conditions are defined as asynchronous exceptions that can be generated at run time by the common language runtime, such as aborted threads, out-of-memory situations, and stack overflows. You can apply the ReliabilityContractAttribute attribute to assemblies, types, and methods.

Use this attribute with the Consistency enumeration to define a reliability contract by documenting the level of reliability in a particular piece of code.

ReaderWriterLockSlim problems
От: Аноним  
Дата: 13.12.13 12:40
Оценка: :))
Ознакомтесь, пожалуйста, с A story of orphaned ReaderWriterLockSlim и
ReaderWriterLockSlim fails on dual-socket environments.
Сразу предупреждаю — впечатлительным 21-летним сеньерам лучше это вообще не читать.

Вкратце:


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

Вперед.
Re[2]: ReaderWriterLockSlim problems
От: Abyx Россия  
Дата: 14.12.13 15:10
Оценка: -1 :)
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Аноним, Вы писали:


А>Почему Lock нельзя просто поместить в блок Try


А>
А>var lockIsHeld = false;
А>try {
А>   rwl.EnterReadLock();
А>   lockIsHeld = true;
А>   // Do work here
А>}
А>finally {
А>   if (lockIsHeld)
А>      rwl.ExitReadLock();
А>}
А>


какая же гадость этот ваш сишарп)
In Zen We Trust
Re[3]: ReaderWriterLockSlim problems
От: Sinix  
Дата: 16.12.13 05:18
Оценка: +2
Здравствуйте, Tom, Вы писали:

S>>Автор создал себе офигенные проблемы уже в момент использования thread.Abort(), всё остальное — уже последствия. Расписывать подробно особого смысла нет, достаточно

Tom>Ээээ на этом месте по подробнее можно?

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

Если поток разделяет свой состояние с остальными потоками — всё ещё хуже: убийство потока может поломать всё приложение. Конечно, можно начать защищаться: добавлять cer, не вызывать "неустойчивые" методы из BCL, писать для всех выделяемых ресурсов финализаторы (например, чтобы если что, освободить "утёкшую" блокировку) etc. По сути, мы получим более продвинутый API для всё той же проблемы — прерывания выполнения в любой точке приложения. Разумеется, со своими тараканами: непредсказуемым порядком освобождения ресурсов, повышенной нагрузкой на финализатор, и, главное, с нерешённой исходной проблемой — см. пример с static-конструкторами из документации. Их-то никак не защитишь

Для более-менее свежего кода, который по полной использует task/await (да даже threadpool), Thread.Abort является чистой диверсией. С учётом штатного CancellationToken — ещё и ненужной.

Tom>thread.Abort используется в куче мест самим фрейсворком.

samius написал выше — всего в паре мест И то, как минимум в SoundPlayer от Abort() точно можно избавиться.
Re[8]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 16.12.13 14:37
Оценка: -1 :)
Здравствуйте, samius, Вы писали:

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


Tom>>Если желание и понимание есть то сделать можно. Если понимания нет то проблемы с юзингом можно получить и без abort-а. Элементарный случай — исключение в конструкторе.

S>Можно подробнее?
А что подробнее то?
Вот минимальный пример.

namespace ConsoleApplication1
{
    public class Foo : IDisposable
    {
        public Foo()
        {
            // Imagine we have got resource here...
            // And then calling something else
            throw new Exception("вай беда бедаё");
        }
        public void Dispose()
        {
            Console.WriteLine("Disposed");
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (new Foo())
                {

                }
            }
            catch (Exception)
            {
                Console.WriteLine("catched");
            }
        }
    }
}
Народная мудрось
всем все никому ничего(с).
Re[9]: ReaderWriterLockSlim problems
От: Sinix  
Дата: 17.12.13 10:41
Оценка: +2
Здравствуйте, Tom, Вы писали:

Tom>Передай это разработчикам сиквела, WCF и IIS-а а то они не вкурсе

Это очень рискованное заявление

Конкретно про ms sql я могу и поспорить, т.к. лет семь назад копался в нюансах реализации hosted clr. Если коротко, по памяти и не совсем корректно (как всегда есть нюансы): при разработке под ms sql нужно соблюдать ряд ограничений, в частности — недопустимо использование разделяемого состояния/static-полей. В том числе и по причине возможного thread.Abort() (хотя там не совсем классический .Abort()).

В принципе, можно на рекомендации наплевать, тогда придётся или плодить сer (бонусом — лаги и невозможность использование untrusted сборок), или бороться с битым состоянием для отдельных запросов (сессий). Оно конечно лечится через выгрузку sqlclr appdomain, но всё равно неприятно.

Про wcf/iis — очень интересно. Где там используется thread.Abort()? Appdomain recycling не считается по вполне понятным причинам
Re[14]: ReaderWriterLockSlim problems
От: drol  
Дата: 22.12.13 07:03
Оценка: +2
Здравствуйте, Tom, Вы писали:

Tom>Подключать стороннюю библиотеку внутрях сиквела... Хм....


Ну а для чего ещё нам нужна CLR внутри SQL Server'а ? Чтобы 2+2 складывать ?

Tom>Ну и уже говорилось защита от асинхронных искоючений давно прилкмана CER&Finally!


И в итоге мы очень быстро дойдём до того, что засунем в эти самые CER\finally почти весь код. Но тогда возникает вопрос. А зачем вообще нужен Thread.Abort(), если он нигде не может пролезть ?
Re[3]: ReaderWriterLockSlim problems
От: drol  
Дата: 16.12.13 19:28
Оценка: 26 (1)
Здравствуйте, Аноним, Вы писали:

А>В каком здесь месте нарисовался Volatile.Write?


То есть с инкрементом owners Вы разобрались. Я Вас правильно понял ?

Теперь об ExitMyLock():

.method private hidebysig instance void  ExitMyLock() cil managed
{
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldflda     int32 System.Threading.ReaderWriterLockSlim::myLock
  IL_0006:  ldc.i4.0
  IL_0007:  call       void [mscorlib]System.Threading.Volatile::Write(int32&,
                                                                       int32)
  IL_000c:  ret
} // end of method ReaderWriterLockSlim::ExitMyLock


Дело в том, что всё не так просто. Начните с того, что посмотрите сколько разных файлов с названием System.Core.dll имеется в наличии у Вашей системы... И где они расположены...

>Передавайте привет декомпилерам, они такие классные, особенно бесплатные.


Привет не 21-летним сеньерам

А>Там не NUMA, там мало памяти (всего 16 Гб).


Объём не имеет никакого отношения к вопросу. Если в системе стоит два Xeon E5-2600, то обратиться к памяти соседа процессор может только через QPI-линк с ним. В отличии от своей собственной, с которой он соединён напрямую непосредственно контроллером памяти.

А>Рихтер предлагает свою библиотеку, она не рабочая.


Как ? И Рихтер тоже ?
Re: ReaderWriterLockSlim problems
От: drol  
Дата: 14.12.13 21:16
Оценка: 22 (1)
Здравствуйте, Аноним, Вы писали:

А>ReaderWriterLockSlim имеет проблемы с грубыми прерываниями потоков


А кто их не имеет-то ??? Любой некооперативный механизм "прерывания" исполнения потока, в общем случае, портит разделяемое состояние.

А>ReaderWriterLockSlim имеет проблемы на серверных конфигурациях (>1 физического процессора)


Он их может и имеет, но вот анализ автора противоречит тому, что вижу лично я.

В декомпилированном ReSharper'ом коде ReaderWriterLockSlim, и с ExitMyLock(), и с инкрементом owners всё в порядке. В первом случае вызывается Volatile.Write(), а во втором все манипуляции выполняются внутри lock'а. Но код мутный. Есть куча внутренних setter'ов для owners, мне было лень смотреть все ли их вызовы внутри lock'ов.

Также у автора зело хитрое железо. Многопроцессорные штуки на семействе Xeon E5-2600 являются NUMA-системами. Согласно документации, там вроде всё должно быть когерентно, но запросто могут быть разложены какие-нибудь тонкие грабли.

А>Краткая переписка с Jeffrey Richter


А переписка-то где ??? Что-то не по глазам...
Re[9]: ReaderWriterLockSlim problems
От: Sinix  
Дата: 10.01.14 10:27
Оценка: 21 (1)
Здравствуйте, scale_tone, Вы писали:

S>>Безопасно, если соблюдать ряд простых правил:

S>>1. Unmanaged-ресурсы аллоцируются и освобождаются через наследника от SafeHandle.

_>А если нет? Что если TrickyMethod, скажем, видео конвертирует, с применением ассемблерных вставок? Что, выгрузка домена в сочетании с Thread.Abort() могут как-то покораптить основной домен?

Аппдомены не изолируют нативный код. Если с ним проблемы, то нет никаких гарантий, что он не покорёжил память процесса в целом. Если с ним нет проблем — нужно следить, чтобы все unmanaged-ресурсы (в том числе аллоцированные области памяти) освобождались при выгрузке домена. Если не рассматривать извраты с CER, остаются только SafeHandle (или другие наследники от CriticalFinalizerObject).

_>Конкретно, разница в том, что в SafeCaller.CallSafely() поток запускался внутри временного домена, а тут, в SafeCaller.CallNotSoSafely() поток запускается (и абортится) в основном.

_>Будет разница в безопасности?

В принципе — разницы быть не должно. Пара оговорок:
1. Я с аппдоменами плотно работал лет 5-6 назад, так что могу и ошибаться
2. Thread.Abort() не гарантирует немедленного завершения потока (он может вообще не завершиться, см ResetAbort()). Как минимум Join() нужен.
Re[7]: ReaderWriterLockSlim problems
От: Sinix  
Дата: 09.01.14 17:24
Оценка: 14 (1)
Здравствуйте, scale_tone, Вы писали:

_>Да вот работает, как ни странно (сам удивился).


Тьфу, ятормоз Если в делегат передать static-метод, код будет работать. Если экземплярный метод, например
    //[Serializable]
    class Program
    {
        static void Main(string[] args)
        { 
            SafeCaller<C>.CallSafely(new Program().DoTricky, null, TimeSpan.FromMinutes(2));           
        }

        public object DoTricky(C c, object o)
        {
            Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
            return null;
        }
    }

    class C { }


— получим или SerialisationException, или десериализованную копию в ThatDomain().

_>Меня, скорее, больше интересовал вопрос, насколько опасно/безопасно делать AppDomain.Unload(). Который, вроде как, должен прибить все потоки, запущенные внутри этого домена. И именно силами Thread.Abort()...

Безопасно, если соблюдать ряд простых правил:
1. Unmanaged-ресурсы аллоцируются и освобождаются через наследника от SafeHandle.
2. Домен с подозрительным кодом в принципе может упасть в любой момент. Если домен выгружен — вызовы методов класса, созданного в этом домене, будут бросать исключения. Хост-домен должен это учитывать и оборачивать вызовы в try-catch.
3. По возможности не надо тасовать потоки между доменами. По памяти — у нас были ошибки, когда AppDomain.Unload прибивал не тот поток.
4. Нужно следить, чтобы подозрительные сборки не загружались в основной домен.

_>И еще интересно, что будет, если опасный метод выполнять в потоке, запущенном вне домена...

Это как? У нас любой managed-код всегда выполняется в рамках текущего домена.
Re[6]: ReaderWriterLockSlim problems
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 09.01.14 12:56
Оценка: 13 (1)
Здравствуйте, Sinix, Вы писали:

_>>Так ограничивать их самостоятельность
Автор: scale_tone
Дата: 22.12.13
можно? Или есть еще подводные камни?

S>А оно вообще будет работать? У нас же делегат не сериализуется и его вызов будет переадресован в исходный домен. Пишу по памяти, проверять надо.

Да вот работает, как ни странно (сам удивился).

S>Но это непринципиально, т.к. передача делегата создаёт другую проблему: сборка вашего trickyMethod будет загружена и в основной домен, и во временный. Избавляемся от передачи делегата — решаем обе


Это понятно. В реальной ситуации метод SafeCaller.CallSafely(), конечно, принимал бы какой-нибудь путь к сборке и имя метода (или просто дефолтный метод из сборки вызывал бы). Я с делегатом написал в целях упрощения и применительно к задаче того топикстартера.

S>Обычно делают чуть иначе:


S>1. Пишут доверенный код, который будет запускать задачи, предоставлять этим задачам api и тд

S>2. Запускают этот код в отдельном домене (доменах) и передают ему список задач на выполнение (например, в виде строк — сборка-тип-метод).
S>3. Если при выполнении одной из задач возникли проблемы — просто прибиваем домен и запускаем заново.

S>Гранулярность (количество доменов/задач на домен) подбирается опытным путём, в зависимости от падучести кода.


Меня, скорее, больше интересовал вопрос, насколько опасно/безопасно делать AppDomain.Unload(). Который, вроде как, должен прибить все потоки, запущенные внутри этого домена. И именно силами Thread.Abort()...
И еще интересно, что будет, если опасный метод выполнять в потоке, запущенном вне домена...
Re[9]: ReaderWriterLockSlim problems
От: drol  
Дата: 18.12.13 09:57
Оценка: 5 (1)
Здравствуйте, Tom, Вы писали:

Tom>Он уже безопасен с некоторыми оговорками. Иначе его бы никогда не впихнули в сиквел.


SQL Server после любого асинхронного исключения в потоке проверяет оный на предмет, а не работал ли тот в момент Ч с разделяемым состоянием. И если работал — весь домен тут же выгружается.
Re: ReaderWriterLockSlim problems
От: Аноним  
Дата: 14.12.13 14:40
Оценка: :)
Здравствуйте, Аноним, Вы писали:

Почему Lock нельзя просто поместить в блок Try

var lockIsHeld = false;
try {
   rwl.EnterReadLock();
   lockIsHeld = true;
   // Do work here
}
finally {
   if (lockIsHeld)
      rwl.ExitReadLock();
}
Re[6]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 16.12.13 14:21
Оценка: -1
Здравствуйте, samius, Вы писали:

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


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


Tom>>А что код фрефмворка обязан вызывать Thread.Abort что бы заабортить поток?

S>Не знаю, что код фреймворка вызывает что бы заабортить поток, но вот мнение Липперта относительно Abort-а
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.

Вы будете удивлены но я абсолютно с ним согласен. Что абсолютно не значит что ThreadAbort зло во всех случаях.
Есть целый класс случаев когда без него просто невозможно обойтись. Это случаи когда вы не владеете кодом который выполняется в вашем потоке в данную минуту.
Примеры ASP.NET, WCF, SQL Server & CLR.
Во всех этих примерах применяется ThreadAbort
Народная мудрось
всем все никому ничего(с).
Re[6]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 16.12.13 14:28
Оценка: -1
ST>Разница меджу TerminateThread и Thread.Abort в том, что первый гарантированно приведет к проблемам, а второй — лишь в некоторых случаях.
Разница там как между взрывом атомной бомбы и игрой детей с зажигалкой
дети с зажигалкой конечно могут проблем наделать но только если они дети несмышлёные.

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

В чём проблема сохранить в переменной а потом захватить ресурс?

ST>Есть ли вообще уверенность, что в случае вызова Thread.Abort будут корректно освобождаться ресурсы в блоке using? Нет, таких гарантий нет, поскольку обеспечить их очень сложно, а проверить — еще сложнее.

Если желание и понимание есть то сделать можно. Если понимания нет то проблемы с юзингом можно получить и без abort-а. Элементарный случай — исключение в конструкторе.

ST>Помимо приведенных ссылок, вот тут тоже можно чутка подробнее об этом почитать: О вреде вызова Thread.Abort.

Сергей я вкурсе твоего блога

Tom>>Или другой случай, случился ресайклинг у IIS App Pool-а, опять же что делать с зависшими запросами....

ST>Когда мы точно знаем, что за код исполняется потоком, то все ОК, но в *общем случае* гарантировать корректное состояние программы после Thread.Abort нельзя.
Я об этом и говорю, нельзя взять и агульно назвать Thread.Abort злом.
Те кто понимает насколько огромный это шаг по сравнению с TerminateThread особенно это понимают.
Ну и как я уже говорил ранее есть случаи где без Thread.Abort невозможно обойтись в принципе.
Народная мудрось
всем все никому ничего(с).
Re[9]: ReaderWriterLockSlim problems
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.12.13 14:39
Оценка: +1
Здравствуйте, Tom, Вы писали:

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


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


Tom>>>Если желание и понимание есть то сделать можно. Если понимания нет то проблемы с юзингом можно получить и без abort-а. Элементарный случай — исключение в конструкторе.

S>>Можно подробнее?
Tom>А что подробнее то?
Tom>Вот минимальный пример.

Пардон, я не вижу в этом примере проблемы с юзингом. Я вижу проблему с пониманием конструкции юзинг.
Re[5]: ReaderWriterLockSlim problems
От: drol  
Дата: 16.12.13 22:37
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Начну с того, что я привел код из памяти проблемной программы.


Не вопрос:

0:003> !dumpil 00007ffd79f53da0 
ilAddr = 00007ffd7a25c207
IL_0000: ldarg.0 
IL_0001: ldflda System.Threading.ReaderWriterLockSlim::myLock
IL_0006: ldc.i4.0 
IL_0007: call System.Threading.Volatile::Write
IL_000c: ret


Так что, для начала, я рекомендую Вам взять назад Ваши слова о декомпиляторах.

А>На этом заканчиваю.


А сколько понтов было в Вашем первом посте...

А>Дальше не отвечаю, убеждать что проблема на твоем фреймворке и домашнем ПэКа отсутствует меня не нужно.


Вы разговариваете сам с собой. Я не знаю существует проблема или нет. Я показываю, что Ваш анализ является поверхностным и бестолковым.
Re[8]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 17.12.13 09:53
Оценка: -1
S>И да, thread.Abort() — это bad practices в чистейшем дистиллированном виде.
Передай это разработчикам сиквела, WCF и IIS-а а то они не вкурсе
Народная мудрось
всем все никому ничего(с).
Re[6]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 17.12.13 11:25
Оценка: :)
А>при этом понятия не имеет что такое acquire\release
И что это такое?
Народная мудрось
всем все никому ничего(с).
Re[12]: ReaderWriterLockSlim problems
От: drol  
Дата: 18.12.13 12:01
Оценка: +1
Здравствуйте, Tom, Вы писали:

Tom>В который кстате прекрасно можно иметь разделяемое состояние без перевода сборки в unsafe или external access.


Можно. Только вот всё это надо специально делать. И за каждым чихом следить. А то, например, подключите какую-нибудь стороннюю библиотеку, а она и слыхом не слыхивала про хостинг в SQL Server'е.
Re: ReaderWriterLockSlim problems
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.01.14 22:20
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А> Вперед.


Звучит как "Бокс!" или даже "Фас!" .

Скажу честно, идея многопоточных вычислений на локах (пусть даже таких новомодных как ReaderWriterLockSlim) — это гнилая идея, на мой взгляд. В любой мало-мальски сложной задаче она выльется в хождение по граблям.

Правильная мнокопоточность делается на более высокоуровневых абстракциях как то:
1. Модель акторов и прочие системы ориентированные на обмен событиями.
2. Функциональные вычисления (туда же монады, продолжения и т.п.).
3. Конечных автоматах.
4. DSL-ях по которым многопоточный код генерируется автоматически.

А уж все виды блокировок и прочей низкоуровневой фигни (вроде многопоточных коллекций) должны быть примитивами реализации вышеперечисленного. Гражданские программисты вообще не должны иметь с ними дела.

Лучше всего если поддержка многопоточности будет встроена к язык (как в Эрланг, например). МС делает некоторые шаги (async) в этом направлении, но как всегда очень робкие.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: ReaderWriterLockSlim problems
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 10.01.14 09:59
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Тьфу, ятормоз Если в делегат передать static-метод, код будет работать.


И правда. В моем случае это была лямбда ((obj, p) => obj.SlowMethod(p)), и она становилась статическим методом, т.к. не юзала членов класса. Стоит лямбду сделать нестатической — все ломается

S>Безопасно, если соблюдать ряд простых правил:

S>1. Unmanaged-ресурсы аллоцируются и освобождаются через наследника от SafeHandle.

А если нет? Что если TrickyMethod, скажем, видео конвертирует, с применением ассемблерных вставок? Что, выгрузка домена в сочетании с Thread.Abort() могут как-то покораптить основной домен?

_>>И еще интересно, что будет, если опасный метод выполнять в потоке, запущенном вне домена...

S>Это как? У нас любой managed-код всегда выполняется в рамках текущего домена.

Это как-то так:
public class SafeCaller<TRickyType> : MarshalByRefObject where TRickyType : new()
{
    public static object CallNotSoSafely(Func<TRickyType, object, object> trickyMethod, object methodParam, TimeSpan timeout)
    {
        object result = null;
        Thread thatThread = null;
        Exception exception = null;

        var domain = AppDomain.CreateDomain("ThatDomain " + Guid.NewGuid());
        try
        {
            var callerType = typeof(SafeCaller<TRickyType>);
            var caller = (SafeCaller<TRickyType>)domain.CreateInstanceAndUnwrap(callerType.Assembly.FullName, callerType.FullName);

            thatThread = new Thread(() =>
                {
                    try
                    {
                        result = caller.CallInSameThread(trickyMethod, methodParam);
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                    }
                });

            thatThread.Start();

            if (!thatThread.Join(timeout))
            {
                throw new TimeoutException("Method timed out!");
            }
        }
        finally
        {
            if (thatThread != null)
            {
                thatThread.Abort();
            }
            AppDomain.Unload(domain);
        }

        if (exception != null)
        {
            throw exception;
        }

        return result;
    }

    private object CallInSameThread(Func<TRickyType, object, object> trickyMethod, object param)
    {
        try
        {
            return trickyMethod(new TRickyType(), param);
        }
        catch (Exception exception)
        {
            // this is a stupid way to workaround not serializable exceptions
            throw new Exception("Tricky method throwed an exception: " + exception.Message);
        }
    }
}


Конкретно, разница в том, что в SafeCaller.CallSafely() поток запускался внутри временного домена, а тут, в SafeCaller.CallNotSoSafely() поток запускается (и абортится) в основном.
Будет разница в безопасности?
Re: ReaderWriterLockSlim problems
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 13.12.13 12:57
Оценка:
Здравствуйте, Аноним, Вы писали:

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


Сталкивались. Наблюдали большое число System.Threading.ReaderWriterCount в Gen2 под нагрузкой. Пока забили.
Re: ReaderWriterLockSlim problems
От: Sinix  
Дата: 15.12.13 11:35
Оценка:
Здравствуйте, Аноним, Вы писали:

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


Автор создал себе офигенные проблемы уже в момент использования thread.Abort(), всё остальное — уже последствия. Расписывать подробно особого смысла нет, достаточно оф. документации:

There is also a chance that a static constructor could be aborted. In rare cases, this might prevent instances of that class from being created in that application domain.

Если вас устраивают такие грабли в продакшне — то и всё остальное пугать не должно.

P.S. А на переписку с Рихтером я бы посмотрел
Re[2]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 15.12.13 13:41
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Аноним, Вы писали:


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


S>Автор создал себе офигенные проблемы уже в момент использования thread.Abort(), всё остальное — уже последствия. Расписывать подробно особого смысла нет, достаточно

Ээээ на этом месте по подробнее можно?
thread.Abort используется в куче мест самим фрейсворком.
Народная мудрось
всем все никому ничего(с).
Re[4]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 16.12.13 13:07
Оценка:
Здравствуйте, samius, Вы писали:

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


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


S>>>Автор создал себе офигенные проблемы уже в момент использования thread.Abort(), всё остальное — уже последствия. Расписывать подробно особого смысла нет, достаточно

Tom>>Ээээ на этом месте по подробнее можно?
Tom>>thread.Abort используется в куче мест самим фрейсворком.
S>Я бы не сказал что в куче
А что код фрефмворка обязан вызывать Thread.Abort что бы заабортить поток?
Народная мудрось
всем все никому ничего(с).
Re[5]: ReaderWriterLockSlim problems
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.12.13 13:34
Оценка:
Здравствуйте, Tom, Вы писали:

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


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


Tom>>>thread.Abort используется в куче мест самим фрейсворком.

S>>Я бы не сказал что в куче
Tom>А что код фрефмворка обязан вызывать Thread.Abort что бы заабортить поток?
Вообще говоря, не обязан. Но я опровергал ваше утверждение о том что thread.Abort используется в куче мест самим фреймворком.
Re[2]: ReaderWriterLockSlim problems
От: Аноним  
Дата: 16.12.13 13:50
Оценка:
Здравствуйте, drol, Вы писали:

D>Здравствуйте, Аноним, Вы писали:


А>>ReaderWriterLockSlim имеет проблемы с грубыми прерываниями потоков


D>А кто их не имеет-то ??? Любой некооперативный механизм "прерывания" исполнения потока, в общем случае, портит разделяемое состояние.


А>>ReaderWriterLockSlim имеет проблемы на серверных конфигурациях (>1 физического процессора)


D>Он их может и имеет, но вот анализ автора противоречит тому, что вижу лично я.


D>В декомпилированном ReSharper'ом коде ReaderWriterLockSlim, и с ExitMyLock(), и с инкрементом owners всё в порядке. В первом случае вызывается Volatile.Write(), а во втором все манипуляции выполняются внутри lock'а. Но код мутный. Есть куча внутренних setter'ов для owners, мне было лень смотреть все ли их вызовы внутри lock'ов.


Код я смотрел здесь:
http://referencesource.microsoft.com/netframework.aspx Net 4.5Update1 View EULA Download


0:022> !DumpIL 000007fbf85a8000
ilAddr = 000007fbf88c7b5f
IL_0000: ldarg.0 
IL_0001: ldc.i4.0 
IL_0002: stfld System.Threading.ReaderWriterLockSlim::myLock
IL_0007: ret


В каком здесь месте нарисовался Volatile.Write? Передавайте привет декомпилерам, они такие классные, особенно бесплатные.


D>Также у автора зело хитрое железо. Многопроцессорные штуки на семействе Xeon E5-2600 являются NUMA-системами. Согласно документации, там вроде всё должно быть когерентно, но запросто могут быть разложены какие-нибудь тонкие грабли.

Там не NUMA, там мало памяти (всего 16 Гб).

А>>Краткая переписка с Jeffrey Richter


D>А переписка-то где ??? Что-то не по глазам...

Ничего полезного. Рихтер предлагает свою библиотеку, она не рабочая.
Re[6]: ReaderWriterLockSlim problems
От: Аноним  
Дата: 16.12.13 14:01
Оценка:
Здравствуйте, Sinix, Вы писали:

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


Tom>>Это с кокого такого перепугу такое делается заявление?

S>Ок, а как ещё назвать решение прерывать поток выполнения в произвольном месте?
Не в произвольном месте, читайте ниже.

Tom>>Отчаяние это TerminateThread а Thread.Abort это более чем кошерное решение проблемы с закрытием и освобождение ресурсов.

S>Как раз с "кошерным" освобождением ресурсов _в общем случае_ у Thread.Abort большие проблемы. Первые же ссылки из гугла
S>http://stackoverflow.com/questions/710070/timeout-pattern-how-bad-is-thread-abort-really
S>http://joeduffyblog.com/2009/03/13/managed-code-and-asynchronous-exception-hardening/
S>http://stackoverflow.com/questions/6382997/is-using-thread-abort-and-handling-threadabortexception-in-net-safe-practice
S>http://geekswithblogs.net/akraus1/archive/2012/10/22/151047.aspx
S>http://onoffswitch.net/when-to-abort-a-thread/
Проблемы у тех, кто не знает как работает Thread.Abort и как уберечь ресурсы от пагубных последствий. А мистер Joe Duffy — вообще автор ReaderWriterLockSlim, на словах — Лев Толстой, а на деле — сами знаете.
Вопреки вопросам от 21-летних сеньеров и ответам от людей сравнимой квалификации, Thread.Abort содержит сложную логику и не прерывает поток где попало. Более того, код можно написать так, чтобы исключить нужные регионы от прерываний.

Контейнеры приложений без абортов вообще сложно представить.

Tom>>Например: Случился таймаут выполнения метода WCF. Вопрос, что делать.

Tom>>Оставлсять всё так как и есть, т.е. продолжить методу висесть или попытаться его заабортить...?
S>Во-первых, поток не является единицей изоляции. Прибивать надо AppDomain/хост-процесс.
S>Во-вторых, в твоих сценариях не предполагается продолжение работы остальных (зависящих от текущего) потоков. У автора исходной статьи такая надежда была
S>Ну, и в-третьих, твои сценарии предполагают чистые (утилитарные) потоки без разделяемого состояния. ReaderWriterLockSlim намекает на полностью противоположное.
Re[7]: ReaderWriterLockSlim problems
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.12.13 14:33
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Если желание и понимание есть то сделать можно. Если понимания нет то проблемы с юзингом можно получить и без abort-а. Элементарный случай — исключение в конструкторе.

Можно подробнее?
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>.method private hidebysig instance void  ExitMyLock() cil managed
D>{
D>  // Code size       13 (0xd)
D>  .maxstack  8
D>  IL_0000:  ldarg.0
D>  IL_0001:  ldflda     int32 System.Threading.ReaderWriterLockSlim::myLock
D>  IL_0006:  ldc.i4.0
D>  IL_0007:  call       void [mscorlib]System.Threading.Volatile::Write(int32&,
D>                                                                       int32)
D>  IL_000c:  ret
D>} // end of method ReaderWriterLockSlim::ExitMyLock
D>


D>Дело в том, что всё не так просто. Начните с того, что посмотрите сколько разных файлов с названием System.Core.dll имеется в наличии у Вашей системы... И где они расположены...


Начну с того, что я привел код из памяти проблемной программы. На этом заканчиваю. Дальше не отвечаю, убеждать что проблема на твоем фреймворке и домашнем ПэКа отсутствует меня не нужно. Спасибо.
Re[8]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 16.12.13 22:45
Оценка:
ST>Ок, давай сделаем небольшую перезагрузку

ST>Рассмотрим такой код:

Я бы такой код назвал конечно наивной реализацией.
В приличных домах принято использовать PrepareConstrainedRegions()


По поводу /// using(var file = new FileStream
По сути проблема тут в самом Disposable паттерне.
В идеале в нём должен быть ещё один метод — метод аллокации ресурса,
тогда все вопросы с конструктором и соответственно присвоением переменной отпали бы.
Хотя и сейчас можно переписать компилятор и если присвоение делается в блоке юзинг то вначале присваивать результат переменной а уж потом вызывать конструктор.

ST>P.S. Достаточно погуглить на предмет количества различных утечек ресурсов (в частности файлов) при наличии Thread.Abort. Самый распространенные фиксятся, но я не думаю, что когда либо в ближайшем будущем .NET Framework станет безопасным с точки зрения асинхронных исключений;0

Он уже безопасен с некоторыми оговорками. Иначе его бы никогда не впихнули в сиквел.
Народная мудрось
всем все никому ничего(с).
Re[9]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 16.12.13 22:56
Оценка:
Забыл совсем сказать, когда бойцы прикручивали CLR к сиквелу — они изобрели HostProtectionAttribute у которого есть MayLeakOnAbort.
Если уже совсем страшно — то можно ориентироваться по нему.
Народная мудрось
всем все никому ничего(с).
Re[8]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 17.12.13 00:43
Оценка:
Кстате твой пример с FileStream безопасен более чем
Народная мудрось
всем все никому ничего(с).
Re[7]: ReaderWriterLockSlim problems
От: Sinix  
Дата: 17.12.13 05:05
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Проблемы с ThreadAbort у людей бывают когда они не понимают что это такое, когда выбрасывается и что с ним вообще делать надо.

Тут уже за меня ответили, причём в основном — гораздо лучше, чем я смогу.

Если суммировать: есть такая штука как bad practices. Их использование в 99.(9)% случаев означает, что у вас _уже_ возникла проблема на предыдущем шаге, но вместо решения самой проблемы вы пытаетесь подпереть её костылём. Ну, как заклеивать лампочку "проверьте двигатель" изолентой, чтоб не мешала. Исключения всегда бывают, но в основном хвастаться смотри ма, без рук "люди не понимают, а я могу" — это чистой воды ребячество.

И да, thread.Abort() — это bad practices в чистейшем дистиллированном виде.

Не, серьёзно — вы правда хотите протащить в продакшн проблемы, которые не воспроизводятся стабильно под отладкой?
Re[9]: ReaderWriterLockSlim problems
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 17.12.13 07:47
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Кстате твой пример с FileStream безопасен более чем


Этот код безопасен с точки зрения синхронных исключений (при учете, что setter свойства Position никтогда не бросает исключений), но с точки зрения асинхронных исключений?

static void UseFile(string filename, int position)
{
    var tmp = new FileStream(filename, FileMode.Open);
    var tmp.Position = position; // тут может упасть ThreadAbort
    using (var file = tmp) {}
}


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


З.Ы. ИМХО, использовать или не использовать Thread.Abort в своем коде — выбор каждого. Если ты считаешь, что потенциальные проблемы (данное обсуждение является примером того, что они возможны) не беспокоят — тогда ОК, вопрос в другом, если это именно твой код, то чем не устроили другие альтернативы? Если же это инфраструктура и выбора нет, то тут, собственно и обсуждать нечего.
Re[10]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 17.12.13 09:51
Оценка:
ST>Этот код безопасен с точки зрения синхронных исключений (при учете, что setter свойства Position никтогда не бросает исключений), но с точки зрения асинхронных исключений?
И и сточки зрения асинхронных он тоже безопасен.
Смысл в том что внутрях при вызове native функций используется SafeHandle по этому в принипе пофиг если исключение будет выкинуто в лдюбом месте.

ST>З.Ы. ИМХО, использовать или не использовать Thread.Abort в своем коде — выбор каждого. Если ты считаешь, что потенциальные проблемы (данное обсуждение является примером того, что они возможны) не беспокоят — тогда ОК

Я тебе про то что вероятность проблем очень сильно преувеличена и что уже давным давно придумали способы борьбы с асинхронными ислючениями в виде CER&Finally блока
Народная мудрось
всем все никому ничего(с).
Re[5]: ReaderWriterLockSlim problems
От: Аноним  
Дата: 17.12.13 10:39
Оценка:
Здравствуйте, Аноним, Вы писали:

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


D>>Здравствуйте, Аноним, Вы писали:


А>>>В каком здесь месте нарисовался Volatile.Write?


D>>То есть с инкрементом owners Вы разобрались. Я Вас правильно понял ?


D>>Теперь об ExitMyLock():


D>>
D>>.method private hidebysig instance void  ExitMyLock() cil managed
D>>{
D>>  // Code size       13 (0xd)
D>>  .maxstack  8
D>>  IL_0000:  ldarg.0
D>>  IL_0001:  ldflda     int32 System.Threading.ReaderWriterLockSlim::myLock
D>>  IL_0006:  ldc.i4.0
D>>  IL_0007:  call       void [mscorlib]System.Threading.Volatile::Write(int32&,
D>>                                                                       int32)
D>>  IL_000c:  ret
D>>} // end of method ReaderWriterLockSlim::ExitMyLock
D>>


D>>Дело в том, что всё не так просто. Начните с того, что посмотрите сколько разных файлов с названием System.Core.dll имеется в наличии у Вашей системы... И где они расположены...


А>Начну с того, что я привел код из памяти проблемной программы. На этом заканчиваю. Дальше не отвечаю, убеждать что проблема на твоем фреймворке и домашнем ПэКа отсутствует меня не нужно. Спасибо.


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

V>Да. Но volatile — это не синхронизация доступа. Это только указание компилятору не кэшировать обращения к переменой.

Это неправда. Операции над volatile-полями включают в себя acquire\release семантику. Посему на них вполне можно делать массу разновидностей синхронизации. Только понимать надо что к чему когда и где...

при этом понятия не имеет что такое acquire\release

в общем — не парься
Re[8]: ReaderWriterLockSlim problems
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 17.12.13 12:46
Оценка:
Здравствуйте, SergeyT., Вы писали:

но если я помечу атрибутом Cer.Success то таких проблем быть не должно?


При возникновении исключительных условий, метод гарантированно завершится успешно. Всегда следует заключать вызываемый метод в конструкцию CER, даже если он вызывается из области, где CER не используется. Метод завершается успешно, если он выполняет то, для чего предназначен. Например, если пометить свойство Count атрибутом ReliabilityContractAttribute(Cer.Success), это подразумевает, что, когда это свойство выполняется в области CER, оно всегда возвращает число элементов в ArrayList и никогда не оставляет внутренние поля неопределенными.

и солнце б утром не вставало, когда бы не было меня
Re: ReaderWriterLockSlim problems
От: Chabster Украина chabster.blogspot.com
Дата: 17.12.13 15:32
Оценка:
Пока вы занимались организацией абортария и обсуждали всякое-разное, я доконал свою проблему и обновил статью: ReaderWriterLockSlim fails on dual-socket environments.
Что в сухом остатке: Microsoft включает "фикс" для ReaderWriterLockSlim в Windows 8.1 и Windows 2012 R2, Windows 2012 первой редакции даже со всеми возможными апдейтами по сей день так и остается с глюкавым классом.
Как я и полагал, изменение состоит в MFENCE перед операцией освобождения спинлока.
Кстати, Volatile.Write реализован по-Майкрософтовски, сначала MFENCE, потом запись. Т.е. он синхронизирует все, кроме ячейки памяти, о которой его просили.
Re[10]: ReaderWriterLockSlim problems
От: drol  
Дата: 18.12.13 10:14
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Забыл совсем сказать, когда бойцы прикручивали CLR к сиквелу — они изобрели HostProtectionAttribute у которого есть MayLeakOnAbort


Вот именно. И если асинхронное исключение прилетит в тот момент, когда работают с тем у чего MayLeakOnAbort или там SharedState, то SQL Server тут же выгрузит домен.
Re[11]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 18.12.13 11:06
Оценка:
Здравствуйте, drol, Вы писали:

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


Tom>>Забыл совсем сказать, когда бойцы прикручивали CLR к сиквелу — они изобрели HostProtectionAttribute у которого есть MayLeakOnAbort

D>Вот именно. И если асинхронное исключение прилетит в тот момент, когда работают с тем у чего MayLeakOnAbort или там SharedState, то SQL Server тут же выгрузит домен.
И? Есть куча классов у которых MayLeakOnAbort=false и пригодных для использования в Safe сборках.
В который кстате прекрасно можно иметь разделяемое состояние без перевода сборки в unsafe или external access.
Народная мудрось
всем все никому ничего(с).
Re[13]: ReaderWriterLockSlim problems
От: Tom Россия http://www.RSDN.ru
Дата: 18.12.13 12:39
Оценка:
Здравствуйте, drol, Вы писали:

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


Tom>>В который кстате прекрасно можно иметь разделяемое состояние без перевода сборки в unsafe или external access.


D>Можно. Только вот всё это надо специально делать. И за каждым чихом следить. А то, например, подключите какую-нибудь стороннюю библиотеку, а она и слыхом не слыхивала про хостинг в SQL Server'е.

Подключать стороннюю библиотеку внутрях сиквела... Хм....
Ну и уже говорилось защита от асинхронных искоючений давно прилкмана CER&Finally!
Народная мудрось
всем все никому ничего(с).
Re[2]: ReaderWriterLockSlim problems
От: drol  
Дата: 22.12.13 06:52
Оценка:
Здравствуйте, Chabster, Вы писали:

C>Microsoft включает "фикс" для ReaderWriterLockSlim в Windows 8.1 и Windows 2012 R2


Ну вот видите

C>Как я и полагал, изменение состоит в MFENCE перед операцией освобождения спинлока.


MFENCE ??? Да ну ? У x86\x86-64, в обычных условиях, достаточно сильная модель памяти. И store через стандартный MOV фактически является volatile write.

Вот, например, System.Core.ni.dll в этом месте:

00007ffe`de72aeb7 488b7f08        mov     rdi,qword ptr [rdi+8]
00007ffe`de72aebb 4885ff          test    rdi,rdi
00007ffe`de72aebe 7592            jne     System_Core_ni+0x2aae52 (00007ffe`de72ae52)
00007ffe`de72aec0 33ff            xor     edi,edi
00007ffe`de72aec2 eb97            jmp     System_Core_ni+0x2aae5b (00007ffe`de72ae5b)
00007ffe`de72aec4 c7433000000000  mov     dword ptr [rbx+30h],0 ds:0000003b`cd3b2ec0=00000001
00007ffe`de72aecb ebd3            jmp     System_Core_ni+0x2aaea0 (00007ffe`de72aea0)
00007ffe`de72aecd 0f1f00          nop     dword ptr [rax]
00007ffe`de72aed0 c6435200        mov     byte ptr [rbx+52h],0
00007ffe`de72aed4 eba6            jmp     System_Core_ni+0x2aae7c (00007ffe`de72ae7c)

Неужели на Xeon генерится что-то другое ?

C>Кстати, Volatile.Write реализован по-Майкрософтовски, сначала MFENCE, потом запись.


И это правильно.

*Пока абстрагируемся от конкретной архитектуры...

C>Т.е. он синхронизирует все, кроме ячейки памяти, о которой его просили.


У не 21-летнего сеньера очень смешные представления о теме

P.S. Да, и ещё. В Вашей обновлённой блог-записи появились какие-то пространные рассуждения о кэше, кэш-линиях и т.п. Так вот, кэш не имеет никакого отношения к вопросу. Вообще. Бо на x86\x86-64 кэш данных когерентен. И посему, никаких дополнительных условий на наблюдаемый сторонними ядрами\процессорами порядок операций не накладывает.
Re[6]: ReaderWriterLockSlim problems
От: drol  
Дата: 22.12.13 07:20
Оценка:
Здравствуйте, Аноним, Вы писали:

А>да и в теме не силен


Трусливый аноним за номером 16 даже нормально отформатировать сообщение не может

Вот ссылка на ту ветку: http://www.rsdn.ru/forum/dotnet/4947187?tree=tree
Автор: drol
Дата: 30.10.12
Re[4]: ReaderWriterLockSlim problems
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 03.01.14 20:03
Оценка:
Здравствуйте, Sinix, Вы писали:

Так я все-таки не понял. Рассматриваем гипотетический сценарий создания собственного Hadoop-а. Джобы на обработку (в виде неких сборок с неким реализованным методом) приходят хрен знает откуда, пишутся хрен знает кем и имеют тенденцию виснуть.

Так ограничивать их самостоятельность
Автор: scale_tone
Дата: 22.12.13
можно? Или есть еще подводные камни?
Re[2]: ReaderWriterLockSlim problems
От: Chabster Украина chabster.blogspot.com
Дата: 07.01.14 23:07
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Аноним, Вы писали:


А>> Вперед.


VD>Звучит как "Бокс!" или даже "Фас!" .

Виноват, завелся сильнооо.

VD>Скажу честно, идея многопоточных вычислений на локах (пусть даже таких новомодных как ReaderWriterLockSlim) — это гнилая идея, на мой взгляд. В любой мало-мальски сложной задаче она выльется в хождение по граблям.


VD>Правильная мнокопоточность делается на более высокоуровневых абстракциях как то:

VD>1. Модель акторов и прочие системы ориентированные на обмен событиями.
VD>2. Функциональные вычисления (туда же монады, продолжения и т.п.).
VD>3. Конечных автоматах.
VD>4. DSL-ях по которым многопоточный код генерируется автоматически.

VD>А уж все виды блокировок и прочей низкоуровневой фигни (вроде многопоточных коллекций) должны быть примитивами реализации вышеперечисленного. Гражданские программисты вообще не должны иметь с ними дела.


VD>Лучше всего если поддержка многопоточности будет встроена к язык (как в Эрланг, например). МС делает некоторые шаги (async) в этом направлении, но как всегда очень робкие.


Влад, все это красивые слова и теории, а реальность такова, что даже эти теории используют в реализациях такие примитивы, как ReaderWriterLockSlim.
Вот банальный пример. System.Web.Util из чистого 4.5 содержал структуру ReadWriteSpinLock. Ее заимствовали многие классы из System.Web. Простейший тест во много потоков демонстрирует, что этот алгоритм не работает. В свежей версии фреймворка его удалили.

Рихтер мне прислал компилирующуюся и якобы рабочую версию своего класса OneManyResourceLock. Под нагрузкой он так же не работает (на домашнем Core i5, 4 ядра) — то нарушает принцип самой блокировки, то блокируется навсегда. И при этом Джефф уверяет, что его кодом пользуются многие в своих продуктах.

Единственная блокировка, которая у меня прошла все тесты — SRW из WinAPI. Но интероп уничтожает все ее прелести.

Работающего решения, которое было бы сравнимо по производительности с ReaderWriterLockSlim я пока не имею.
Re[3]: ReaderWriterLockSlim problems
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.01.14 01:04
Оценка:
Здравствуйте, Chabster, Вы писали:

C>Рихтер мне прислал компилирующуюся и якобы рабочую версию своего класса OneManyResourceLock. Под нагрузкой он так же не работает (на домашнем Core i5, 4 ядра) — то нарушает принцип самой блокировки, то блокируется навсегда. И при этом Джефф уверяет, что его кодом пользуются многие в своих продуктах.


Лучше всего выложить сюда тесты демонстрирующие падение (или что там происходит). Тогда можно будет предметно обсудить проблему.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: ReaderWriterLockSlim problems
От: drol  
Дата: 08.01.14 04:29
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Лучше всего выложить сюда тесты демонстрирующие падение (или что там происходит). Тогда можно будет предметно обсудить проблему.


Посмотрел одним глазом OneManyResourceLock.cs что в github'е Рихтера.

Действительно, в общем случае с формальной точки зрения это работать не должно. Там разделяемое состояние читается без задания порядка, путём обычного копирования ref-параметра в локальную переменную
Re[5]: ReaderWriterLockSlim problems
От: Sinix  
Дата: 09.01.14 04:58
Оценка:
Здравствуйте, scale_tone, Вы писали:

_>Так я все-таки не понял. Рассматриваем гипотетический сценарий создания собственного Hadoop-а. Джобы на обработку (в виде неких сборок с неким реализованным методом) приходят хрен знает откуда, пишутся хрен знает кем и имеют тенденцию виснуть.


_>Так ограничивать их самостоятельность
Автор: scale_tone
Дата: 22.12.13
можно? Или есть еще подводные камни?

А оно вообще будет работать? У нас же делегат не сериализуется и его вызов будет переадресован в исходный домен. Пишу по памяти, проверять надо.

Но это непринципиально, т.к. передача делегата создаёт другую проблему: сборка вашего trickyMethod будет загружена и в основной домен, и во временный. Избавляемся от передачи делегата — решаем обе

Обычно делают чуть иначе:

1. Пишут доверенный код, который будет запускать задачи, предоставлять этим задачам api и тд
2. Запускают этот код в отдельном домене (доменах) и передают ему список задач на выполнение (например, в виде строк — сборка-тип-метод).
3. Если при выполнении одной из задач возникли проблемы — просто прибиваем домен и запускаем заново.

Гранулярность (количество доменов/задач на домен) подбирается опытным путём, в зависимости от падучести кода.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.