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[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.

Re[9]: ReaderWriterLockSlim problems
От: drol  
Дата: 18.12.13 09:57
Оценка: 5 (1)
Здравствуйте, Tom, Вы писали:

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


SQL Server после любого асинхронного исключения в потоке проверяет оный на предмет, а не работал ли тот в момент Ч с разделяемым состоянием. И если работал — весь домен тут же выгружается.
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[12]: ReaderWriterLockSlim problems
От: drol  
Дата: 18.12.13 12:01
Оценка: +1
Здравствуйте, Tom, Вы писали:

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


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

А> Вперед.


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

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

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

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

Лучше всего если поддержка многопоточности будет встроена к язык (как в Эрланг, например). МС делает некоторые шаги (async) в этом направлении, но как всегда очень робкие.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
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. Если при выполнении одной из задач возникли проблемы — просто прибиваем домен и запускаем заново.

Гранулярность (количество доменов/задач на домен) подбирается опытным путём, в зависимости от падучести кода.
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[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[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() поток запускается (и абортится) в основном.
Будет разница в безопасности?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.