Re[11]: секунда WTF (lock)
От: fddima  
Дата: 28.01.17 16:47
Оценка: 33 (2)
Здравствуйте, Sinix, Вы писали:

F>> PS: А Dictionary — зачем там?

S>http://stackoverflow.com/questions/3366376/are-net-switch-statements-hashed-or-indexed
Понял. То ли не знал, то ли забыл... Но рослин так не делает. Вместо этого он считает хэш строки, и генерирует код который сравнивает хэши. Начинает так делать он только если есть как минимум 7 кейсов.

Ну т.е. для:
        public static int Main(string[] args)
        {
            switch (args[0])
            {
                case "s1": return 1;
                case "s2": return 2;
                case "s3": return 3;
                case "s4": return 4;
                case "s5": return 5;
                case "s6": return 6;
                case "s7": return 7;
            }
            return 0;
        }


Он генерирует:

public static int Main(string[] args)
{
    string text = args[0];
    uint num = <PrivateImplementationDetails>.ComputeStringHash(text);
    if (num <= 139573449u)
    {
        if (num != 89240592u)
        {
            if (num != 106018211u)
            {
                if (num == 139573449u)
                {
                    if (text == "s1")
                    {
                        return 1;
                    }
                }
            }
            else if (text == "s3")
            {
                return 3;
            }
        }
        else if (text == "s2")
        {
            return 2;
        }
    }
    else if (num <= 173128687u)
    {
        if (num != 156351068u)
        {
            if (num == 173128687u)
            {
                if (text == "s7")
                {
                    return 7;
                }
            }
        }
        else if (text == "s6")
        {
            return 6;
        }
    }
    else if (num != 189906306u)
    {
        if (num == 206683925u)
        {
            if (text == "s5")
            {
                return 5;
            }
        }
    }
    else if (text == "s4")
    {
        return 4;
    }
    return 0;
}


Где ComputeStringHash:

.method assembly hidebysig static 
    uint32 ComputeStringHash (
        string s
    ) cil managed 
{
    // Method begins at RVA 0x21a8
    // Code size 44 (0x2c)
    .maxstack 2
    .locals init (
        [0] uint32,
        [1] int32
    )

    IL_0000: ldarg.0
    IL_0001: brfalse.s IL_002a

    IL_0003: ldc.i4 -2128831035
    IL_0008: stloc.0
    IL_0009: ldc.i4.0
    IL_000a: stloc.1
    IL_000b: br.s IL_0021
    // loop start (head: IL_0021)
        IL_000d: ldarg.0
        IL_000e: ldloc.1
        IL_000f: callvirt instance char [mscorlib]System.String::get_Chars(int32)
        IL_0014: ldloc.0
        IL_0015: xor
        IL_0016: ldc.i4 16777619
        IL_001b: mul
        IL_001c: stloc.0
        IL_001d: ldloc.1
        IL_001e: ldc.i4.1
        IL_001f: add
        IL_0020: stloc.1

        IL_0021: ldloc.1
        IL_0022: ldarg.0
        IL_0023: callvirt instance int32 [mscorlib]System.String::get_Length()
        IL_0028: blt.s IL_000d
    // end loop

    IL_002a: ldloc.0
    IL_002b: ret
} // end of method '<PrivateImplementationDetails>'::ComputeStringHash


К сожалению ilspy не хочет видеть PrivateImplementationDetails (при декомпиляции в C#).
Отредактировано 28.01.2017 16:48 Mystic Artifact . Предыдущая версия .
Re[7]: секунда WTF (lock)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 28.01.17 17:28
Оценка: 50 (1)
Здравствуйте, Sinix, Вы писали:

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



S>>>Да ладно? Сначала матчасть, затем на бгоневичнок. Порядок важен

S>>Этот инструмент не покажет потенциальный дедлок, а покажет только случившийся и пойманный на машине разработчика. Т.е. когда уже помидоры в смятку.
S>А, это тоже есть. Было, в смысле. Typemock Racer, CHESS, Jinx — их популярность как бы намекает на актуальность проблемы и эффективность инструментов. Серьёзно, написать корректно сразу — на порядки выгодней, чем надеяться поймать гейзенбаги тестированием.
А что, сопровождение и развитие уже не в почете?

S>>Да, я использую level-ы синкрутов, как по первой ссылке. Но даже при этом контроль времени выполнения при попытке захвата в неверном порядке не помешает. ИМХО. Уже на стадии прогона тестов я знаю что дедлока не будет.

S>Неа. Ты знаешь, что дедлок не воспроизводится с некоторой вероятностью, не больше того. С учётом того, что дедлоки уже ловились раньше, как ты пишешь — не самая обнадёживающая информация
Разве я написал что они ловились? Нет, я написал что они ловились на этапе тестирования — а значит еще до коммита. Это раз.
Второе — проверка кидает исключение не в тот момент, когда дедлок возникает, а в момент, когда код первый раз проходит по месту, где делается вложенный lock с синкрутом неверного уровня. Т.е. от первого прохода по коду, где потенциально когда-нибудь задедлочит.

S>Вероятность конечно можно повысить — собирать зависимые локи (один lock берётся внутри другого) за всё время выполнения процесса и искать петли в графе зависимостей. К сожалению, это не спасёт от десятков прочих ошибок типа неявного разделяемого состояния, обращения к ресурсу вне локов, использования thread-local-переменных или блокировок вперемешку с async. Выгодней сразу свести разделяемое состояние к минимуму и по минимуму же использовать примитивы синхронизации. Меньше мест, где можно ошибиться — меньше ошибок — профит.

Петли в графе зависимостей убраны с помощью расстановки уровней. Их нет потому что нет. И доказано что весь код берет локи в правильном порядке просто фактом прохода по этому коду в интеграционном тесте.
От блокировок вперемешку с async спасает ключевое слово lock, к которому я и пытаюсь подрулить с помощью недокументированных возможностей. А сейчас мне в этом рантайм проверка помогает.

S>Ну и перехватывать локи, разумеется не через хак с компилятором, а с Fody/PostSharp. И не только Monitor.*, но и спинлоки, wait handles и тыды. Надёжней будет. Собственно, уже.

Еще раз. Проверка уровней ловит первый захват в неверном порядке, саму потенциальную ситуацию. PostSharp ловит дедлок в рантайме (а значит, не создание потенциальной ситуации, он ничего не знает о потенциальных ситуациях, нет маркировки уровней), а при самом дедлоке, непосредственно вместо блокировки. А это с большой вероятностью случится после коммита изменений, а то и вообще в продакшне. Давай все-таки, ты сначала поймешь то, о чем я пишу, потом будешь советовать. Без обид? А то твои советы выглядят поверхностными.

S>>И представь, я не занимаюсь целенаправленным достижением дедлоков, но контроль срабатывает довольно часто.

S>Ну, бардак в проекте, без обид. Я за 10 лет сталкивался с неожиданными дедлоками ровно два раза. Оба раза товарищ разработчик считал, что большие красные буквы в мануале — это не для него.
В тестах контроль срабатывал, в тестах (до коммита еще). Если бы такая штука была у твоего товарища разработчика, то ты бы не увидел и этих дедлоков. Полагаю, что PostSharp у него все же стоит? Нет?

Вообще, чего я оправдываюсь? Я не чувствую что набедокурил.
Re[12]: секунда WTF (lock)
От: rameel https://github.com/rsdn/CodeJam
Дата: 28.01.17 17:31
Оценка: 16 (1)
Здравствуйте, fddima, Вы писали:

F>К сожалению ilspy не хочет видеть PrivateImplementationDetails (при декомпиляции в C#).


ComputeStringHash
/// <summary>
/// Compute the hashcode of a sub string using FNV-1a
/// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
/// </summary>
/// <remarks>
/// This method should be kept consistent with MethodBodySynthesizer.ConstructStringSwitchHashFunctionBody
/// The control flow in this method mimics lowered "for" loop. It is exactly what we want to emit
/// to ensure that JIT can do range check hoisting.
/// </remarks>
internal static uint ComputeStringHash(string text)
{
    uint hashCode = 0;
    if (text != null)
    {
        hashCode = unchecked((uint)2166136261);

        int i = 0;
        goto start;

    again:
        hashCode = unchecked((text[i] ^ hashCode) * 16777619);
        i = i + 1;

    start:
        if (i < text.Length)
            goto again;
    }
    return hashCode;
}
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[8]: секунда WTF (lock)
От: Sinix  
Дата: 28.01.17 19:05
Оценка:
Здравствуйте, samius, Вы писали:

S>А что, сопровождение и развитие уже не в почете?

Ну вот не срослось ни у одного из проектов, хотя всей магии там — только инжекция кода в рантайме / при компиляции. Не бог весть какая сложная задача.


S>Разве я написал что они ловились? Нет, я написал что они ловились на этапе тестирования — а значит еще до коммита. Это раз.

Да это понятно. Я про фразу "я знаю что дедлока не будет". Чересчур оптимистично как-то


S>И доказано что весь код берет локи в правильном порядке просто фактом прохода по этому коду в интеграционном тесте.

Не "доказано", а "не поймано", сорри за занудство. Самые частые проблемы — наличие нескольких иерархий локов, неявные блокировки или "ослабленные" иерархии, в которых разрешается пропускать часть локов. И то и другое, и третье поймать не так просто Я про что-то типа такого.
        var x = new object();
        lock (x)
        {
            Task.Run(() => { lock (x) { } }).Wait();
        }


S>От блокировок вперемешку с async спасает ключевое слово lock, к которому я и пытаюсь подрулить с помощью недокументированных возможностей.

Если бы спасало См пример выше.


S>Еще раз. Проверка уровней ловит первый захват в неверном порядке, саму потенциальную ситуацию. PostSharp ловит дедлок в рантайме

Не только фактический дедлок, он хранит граф объектов и проверяет на петли. Там слегка упрощённый анализ емнип, но за основу можно взять

S> (а значит, не создание потенциальной ситуации, он ничего не знает о потенциальных ситуациях, нет маркировки уровней)

Маркировка уровней не нужна для обнаружения потенциального дедлока. Достаточно поймать образование петли в графе, узлы которого захватывались разными потоками. Можно запретить reentrancy — тогда даж владение узлов проверять не нужно. Ну и уж точно не нужно требовать одновременности локировок. Просто собирать и достраивать граф за всё время жизни процесса с тестами — отлично рабтает. Я с этой фигнёй игрался лет так 5 назад. Ну да, ошибки ловятся, но на практике толку от этого немного. Заменить блокирующие ожидания на CPS выгоднее получается.


S>Вообще, чего я оправдываюсь? Я не чувствую что набедокурил.

В смысле оправдываешься? Мы вроде опытом делимся, а не спорим
Re: секунда WTF (lock)
От: romangr Россия  
Дата: 28.01.17 19:36
Оценка:
Здравствуйте, samius, Вы писали:
S>З.Ы.2 Правильные ответы не знаю.

А вообще кто-нибудь знает, зачем сделали возможность делать lock на произвольном объекте?
Сделали бы только Monitor и все только с его экземплярами?
... << RSDN@Home (RF) 1.2.0 alpha 5 rev. 67>>
Re[2]: секунда WTF (lock)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.01.17 19:38
Оценка: +1
Здравствуйте, romangr, Вы писали:

R>А вообще кто-нибудь знает, зачем сделали возможность делать lock на произвольном объекте?

R>Сделали бы только Monitor и все только с его экземплярами?

Содрали с жабы не включая моск.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[8]: секунда WTF (lock)
От: Слава  
Дата: 28.01.17 20:03
Оценка:
Здравствуйте, samius, Вы писали:

S>Вообще, чего я оправдываюсь? Я не чувствую что набедокурил.


А есть ли у вас возможность просто собирать дампы на клиенте? Ну чтобы если лок висит больше какого-то разумного времени, то убивать процесс целиком и снимать дамп с помощью Windows Error Reporting
Re[9]: секунда WTF (lock)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 28.01.17 20:12
Оценка: 25 (1)
Здравствуйте, Sinix, Вы писали:

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


S>>А что, сопровождение и развитие уже не в почете?

S>Ну вот не срослось ни у одного из проектов, хотя всей магии там — только инжекция кода в рантайме / при компиляции. Не бог весть какая сложная задача.
Что именно? Сопровождение не срослось?


S>>Разве я написал что они ловились? Нет, я написал что они ловились на этапе тестирования — а значит еще до коммита. Это раз.

S>Да это понятно. Я про фразу "я знаю что дедлока не будет". Чересчур оптимистично как-то
Мой оптимизм с инструментальным контролем проверки уровня немного оптимистичнее твоего без онного.


S>>И доказано что весь код берет локи в правильном порядке просто фактом прохода по этому коду в интеграционном тесте.

S>Не "доказано", а "не поймано", сорри за занудство. Самые частые проблемы — наличие нескольких иерархий локов, неявные блокировки или "ослабленные" иерархии, в которых разрешается пропускать часть локов. И то и другое, и третье поймать не так просто Я про что-то типа такого.
S>
S>        var x = new object();
S>        lock (x)
S>        {
S>            Task.Run(() => { lock (x) { } }).Wait();
S>        }
S>

Хорошо, я не имел в виду все возможные типы блокировок. А PostSharp такую вычислит?

S>>От блокировок вперемешку с async спасает ключевое слово lock, к которому я и пытаюсь подрулить с помощью недокументированных возможностей.

S>Если бы спасало См пример выше.
я про
lock (x)
{
   await Task.Run(...);
}



S>>Еще раз. Проверка уровней ловит первый захват в неверном порядке, саму потенциальную ситуацию. PostSharp ловит дедлок в рантайме

S>Не только фактический дедлок, он хранит граф объектов и проверяет на петли. Там слегка упрощённый анализ емнип, но за основу можно взять
Он выстрелит раньше, чем случатся обстоятельства, ведущие без него к дедлоку?
Так вот, маркировка уровней избавляяет от необходимости этот граф строить и проверять на петли. Единственный контроль, который нужен — что порядок уровней не нарушается при очередном захвате.

S>> (а значит, не создание потенциальной ситуации, он ничего не знает о потенциальных ситуациях, нет маркировки уровней)

S>Маркировка уровней не нужна для обнаружения потенциального дедлока. Достаточно поймать образование петли в графе, узлы которого захватывались разными потоками. Можно запретить reentrancy — тогда даж владение узлов проверять не нужно. Ну и уж точно не нужно требовать одновременности локировок. Просто собирать и достраивать граф за всё время жизни процесса с тестами — отлично рабтает. Я с этой фигнёй игрался лет так 5 назад. Ну да, ошибки ловятся, но на практике толку от этого немного. Заменить блокирующие ожидания на CPS выгоднее получается.
Что бы проверять петли графа — его надо строить (в рантайме), делать проверку на петлю при каждой попытке блокировки, достраивать ребро при удачном захвате, удалять при выходе из лока.
А уровень проверяется одним сравнением целого с целым. Если не считать обращение к [ThreadStatic] полю.

CPS — это continuation-ы? Таски? Не всегда это выгоднее.

S>>Вообще, чего я оправдываюсь? Я не чувствую что набедокурил.

S>В смысле оправдываешься? Мы вроде опытом делимся, а не спорим

А ощущение что меня сейчас накажут если не отверчусь
Re[9]: секунда WTF (lock)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 28.01.17 20:24
Оценка:
Здравствуйте, Слава, Вы писали:

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


S>>Вообще, чего я оправдываюсь? Я не чувствую что набедокурил.


С>А есть ли у вас возможность просто собирать дампы на клиенте? Ну чтобы если лок висит больше какого-то разумного времени, то убивать процесс целиком и снимать дамп с помощью Windows Error Reporting

Нету такой возможности.
Re[10]: секунда WTF (lock)
От: Sinix  
Дата: 29.01.17 10:40
Оценка:
Здравствуйте, samius, Вы писали:

S>Что именно? Сопровождение не срослось?

Ну да — все проекты, что перечислил выше умерли. Даже опенсорсный CHESS — не нужныи оно никому оказалось.


S>Мой оптимизм с инструментальным контролем проверки уровня немного оптимистичнее твоего без онного.

Есть такое дело Точнее, я рассчитываю на то, что если при написании кода нет блокирующих ожиданий и петель, то и о дедлоках заботиться незачем. Ну, а если чего вдруг и проскользнёт — то они обломится на await с timeout-ами и этого будет достаточно для диагностики. Пока что этот подход не подводил, смысла дёргаться не вижу



S>Что бы проверять петли графа — его надо строить (в рантайме), делать проверку на петлю при каждой попытке блокировки, достраивать ребро при удачном захвате, удалять при выходе из лока.

S>А уровень проверяется одним сравнением целого с целым. Если не считать обращение к [ThreadStatic] полю.

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


S>CPS — это continuation-ы? Таски? Не всегда это выгоднее.

О, а давай пример тогда Хоть какой. А то у меня пока в основном обратные примеры копятся — без сложных локов проще.


S>А ощущение что меня сейчас накажут если не отверчусь

Упс
Re[11]: секунда WTF (lock)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 29.01.17 13:28
Оценка: 25 (1)
Здравствуйте, Sinix, Вы писали:

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


S>>Что именно? Сопровождение не срослось?

S>Ну да — все проекты, что перечислил выше умерли. Даже опенсорсный CHESS — не нужныи оно никому оказалось.
Ок, понял.


S>>Мой оптимизм с инструментальным контролем проверки уровня немного оптимистичнее твоего без онного.

S>Есть такое дело Точнее, я рассчитываю на то, что если при написании кода нет блокирующих ожиданий и петель, то и о дедлоках заботиться незачем. Ну, а если чего вдруг и проскользнёт — то они обломится на await с timeout-ами и этого будет достаточно для диагностики. Пока что этот подход не подводил, смысла дёргаться не вижу

Конечно незачем если при написании нет блокирующих ожиданий. А вот у меня проект чуть ли не весь из блокирующих ожиданий. А что бы не было петель — контроль.

S>>А уровень проверяется одним сравнением целого с целым. Если не считать обращение к [ThreadStatic] полю.


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

Хорошо, а чего будет достаточно?

S>>CPS — это continuation-ы? Таски? Не всегда это выгоднее.

S>О, а давай пример тогда Хоть какой. А то у меня пока в основном обратные примеры копятся — без сложных локов проще.
Дык я не спорю что без них проще.
Текущий проект, над которым работаю — сервис, обслуживающий коллбэки из драйвера файловой системы. Типа смарткэша для облачного файлового хранилища (корпоративного, не личного).
Блокировками (в том числе) защищена единая модель дерева файлов в памяти. В следующей версии мне дали добро на переход к модели, построенной по функциональным принципам (на неизменяемых данных), что бы уйти от блокировок при обращении к модели. Но модель дерева файлов — не единственное, что требует блокировок.
Re[12]: секунда WTF (lock)
От: Sinix  
Дата: 29.01.17 14:00
Оценка: 20 (1)
Здравствуйте, samius, Вы писали:

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

S>Хорошо, а чего будет достаточно?
Ну как минимум — отслеживание всех блокирующих вызовов (их не так уж и много). Иначе будут неловящиеся дедлоки, пример уже подкидывал. В идеале — ещё и трассировку async-callback-ов добавить, через async local. Но это уже по желанию.



S>Текущий проект, над которым работаю — сервис, обслуживающий коллбэки из драйвера файловой системы. Типа смарткэша для облачного файлового хранилища (корпоративного, не личного).

S>Блокировками (в том числе) защищена единая модель дерева файлов в памяти.

А. Мы такое когда-то делали на очередях и cqrs-style (хотя тогда cqrs ещё в моде вроде не был... что-то подобное короч) уведомлениях об изменении данных. Но у нас не было требования консистентности, т.е. модель в памяти могла отражать содержимое файлов с некоторой задержкой. Ну, и данные делились так, чтобы отдельные части можно было безопасно обновлять параллельно, каждая часть обрабатывалась в один поток. В общем, 9/10 всех костылей было убрано ещё в момент проектирования и работать было сплошным удовольствием.

Если требование консистентности есть — то да, жизнь становится заметно интереснее
Отредактировано 29.01.2017 14:01 Sinix . Предыдущая версия .
Re[13]: секунда WTF (lock)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 29.01.17 15:29
Оценка: +1
Здравствуйте, Sinix, Вы писали:

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


S>>Хорошо, а чего будет достаточно?

S>Ну как минимум — отслеживание всех блокирующих вызовов (их не так уж и много). Иначе будут неловящиеся дедлоки, пример уже подкидывал. В идеале — ещё и трассировку async-callback-ов добавить, через async local. Но это уже по желанию.
Да, при обращении к блокирующим асинхронным вызовам (например, сервера) могу потребовать отсутствия захватов у вызывающего потока, раз я их (захваты) отслеживаю.
Хорошая мысль, спасибо. Хоть это требование должно быть не забыто добавлено в код руками, оно просигналит что блокирующий код вызван из под lock-а.


S>>Текущий проект, над которым работаю — сервис, обслуживающий коллбэки из драйвера файловой системы. Типа смарткэша для облачного файлового хранилища (корпоративного, не личного).

S>>Блокировками (в том числе) защищена единая модель дерева файлов в памяти.

S>А. Мы такое когда-то делали на очередях и cqrs-style (хотя тогда cqrs ещё в моде вроде не был... что-то подобное короч) уведомлениях об изменении данных. Но у нас не было требования консистентности, т.е. модель в памяти могла отражать содержимое файлов с некоторой задержкой. Ну, и данные делились так, чтобы отдельные части можно было безопасно обновлять параллельно, каждая часть обрабатывалась в один поток. В общем, 9/10 всех костылей было убрано ещё в момент проектирования и работать было сплошным удовольствием.


S>Если требование консистентности есть — то да, жизнь становится заметно интереснее

Хм, навскидку сложно сказать, может ли драйвер файловой системы теоретически работать с cqrs, все-таки какие-то гарантии требует и сам Windows при обращении к драйверу. Создание файла подразумевает возврат хэндла созданного файла, что вроде бы уже выпадает из cqrs. Можно ли там схитрить — фиг знает.
Re: секунда WTF (lock)
От: fddima  
Дата: 29.01.17 23:06
Оценка:
Здравствуйте, samius, Вы писали:

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

Механизм используемый тобой слишком слоден доя новичков имхо, но, имхо, на самом деле — твоя практика тут... бесценна. Ты ж ведь из тех кто юзает дотнет почти сгачала если я не ошибаюсь, а вае "знакомство" с Sinix волей судеб случилось токс щас? Хотя это дико — я давно ставлб оценки тока ему и рслн меня режет за межуусобничество — но я его в глаза не знаю...
А и пофиг. Мне всегда на них было пофиг.
Просто если есть реально хорошмй опыт — имхо — его стоит описать, тем более если есть примеры.
Безусловно — нужно твоё желание, нужно вообще видение этого как статьи. Я лично доя себя понял что вы межлу собой поговорили о чем-то. Не то. Ну не то что-бы у мну фантазия не работала, но это другое.
@samius, если ты готов поделиться опытом — я думаю как минимум это оценят даже "смежники", вдобавок задача что ты озвучил — два раза как выбивается в интересные — она ведь из области того запрещённого кода где некоторые считаю что никто кроме... (неважне чего — важен факт).
Мне кажется если иы осилишь аггрегировать свой опыт — это было бы интересно.
Нафуя? Х.з.
Re[2]: секунда WTF (lock)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 30.01.17 10:27
Оценка: 79 (3)
Здравствуйте, fddima, Вы писали:

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


F> Возможно ли такое, что ты сврй подход щаоаенсорсишь и сделаешь нормальное объяснение как этим пользоваться?

Заопенсосить возможно, но маловероятно. Куда вероятнее пост в некроблоге, но тоже, фиг его знает.
F> Смотри — первый бенефит — оно нафиг никому не надо.
F> Второй бенефит — ты потратишь время впустую.
Верно, согласен.
На самом деле опенсорс форма не нужна. Там исходников край 400 линий и их проще вставить в потенциально проблемный проект, чем тащить лишнюю зависимость. Да и есть вопросы с организацией подмены встроенного Monitor. Использование using вместо lock имеет свои недостатки (например, разрешает await внутри блока), требует мотивированного политического решения использовать в прокете именно этот конструкт. Использование lock требует задействования недокументированных возможностей компилятора, да и не известно, как ведет себя при использовании в разных сборках. Скорее всего — никак, т.е. в каждой сборке прокта придется вписывать (или включать исходники) для подмены родного Monitor-а.
Самое ценное здесь — идея. До нее дошел сам, правда, не с нуля. Но на авторство не претендую. Спасибо Sinix-у за ссылку, там идея неплохо описана.

Все что осталось (не тянет на статью) — история того как я дошел, мысли.

F> Механизм используемый тобой слишком слоден доя новичков имхо, но, имхо, на самом деле — твоя практика тут... бесценна. Ты ж ведь из тех кто юзает дотнет почти сгачала если я не ошибаюсь, а вае "знакомство" с Sinix волей судеб случилось токс щас? Хотя это дико — я давно ставлб оценки тока ему и рслн меня режет за межуусобничество — но я его в глаза не знаю...

Да, я юзаю дотнет почти сначала, точнее, с первой общедоступной беты. На rsdn зарегистрировался где-то в 2005 (до этого с годик лишь читал). С Sinix-ом мы пересекаемся часто последние несколько лет (но не регулярно), а "в глаза" я вообще никого не знаю.

F> А и пофиг. Мне всегда на них было пофиг.


F> Просто если есть реально хорошмй опыт — имхо — его стоит описать, тем более если есть примеры.

F> Безусловно — нужно твоё желание, нужно вообще видение этого как статьи. Я лично доя себя понял что вы межлу собой поговорили о чем-то. Не то. Ну не то что-бы у мну фантазия не работала, но это другое.
F> @samius, если ты готов поделиться опытом — я думаю как минимум это оценят даже "смежники", вдобавок задача что ты озвучил — два раза как выбивается в интересные — она ведь из области того запрещённого кода где некоторые считаю что никто кроме... (неважне чего — важен факт).
F> Мне кажется если иы осилишь аггрегировать свой опыт — это было бы интересно.
F> Нафуя? Х.з.

Разве что, ради интереса. На самом деле, оно не каждому и не в каждом проекте нужно.

Итак, вот как было. Году в 2003-м усиленно следил за codeproject.com, и встретил там как раз статью о подмене Monitor (именно той, что в старте топика) для диагностики дедлоков. Статью я уже искал ранее, вот и сейчас не нашел. Там именно что при попытке захвата проверялся граф уже захваченных локов, который при удачном захвате достраивался (через захват глобального синкрута). Это все работало только для дедлоков вида
// thread 1
lock (a)
  lock (b) {}

// thread 2
lock (b)
  lock (a) {}

с поправкой на неопределенную глубину вложений. И при обнаружении дедлока в момент захвата сразу кидается исключение (со стеком и шлюхами). Все круто, исключение вместо зависания — это определенно прогресс. Но дедлок — это такая история, которая может то ли случиться, то ли нет, то ли в этом году, то ли в следующем, то ли на машине разработчика, то ли у юзера, который то ли забьет, то ли нет. На счет этого статья более ничего не предлагала. Тогда я статью почитал и забыл. Больше ее не видел.

История продолжилась пару лет назад, когда в бете текущего проекта искали злой дедлок, который просто вымораживал винду на машинах пользователей. Вспомнил я про ту статью, накидал подобную диагностику, заменил все lock-и на using-и и нифига. Дедлок есть, а исключения — нет. Оказалось, что все последовательности захватов были реализованы верно, но вот был блокирующий вызов проводника и делался он из под захвата. Проводник вызывал приложение и упирался в этот же захват (на самом деле цепочка длинее). Ну да ладно, дедлок нашелся, а прифигаченный контроль отдирать не стал. А контроль потом нет-нет, да и стал срабатывать, преимущественно у пользователей (беты) после фиксов, да дополнений фич, сделанных впопыхах. Так встала задача раннего обнаружения дедлоков, т.е. еще до момента когда появится петля в графе захватов.

Рассуждения следующие: все синкруты в дотнете, которые ходят на Monitor.Enter, равноправны. От этого и проблемы и неопределенности во времени возникновения дедлока. Разработчик каким-то образом представляет правильную последовательность взятия синкрутов своих объектов, но у него нет инструментального контроля проверки этой правильности. Равноправность (следовательно неопределенность последовательности взятия локов) надо исключить. Если нужно взять два равноправных лока, то значит, у этих локов должны быть разные приоритеты их взятия.

Далее есть сценарии, при которых требуется захватить синкруты одного объекта, другого (другого уровня). Либо только одного, либо двух, либо после захвата чего-либо может выясниться, что нужно захватить еще что-то, а может и не выясниться. Исходим из того, что разработчик в курсе, какие бывают проблемы от некорректной последовательности захватов, и может сам корректно определить порядок и записать его в тетрадке, или где-нибудь еще. И написать в склерозник, что при каждом изменении надо удостоверяться в правильности порядка. А вот это проблема. При рефакторинге правильную последовательность легко потерять и узнать об этом в продакшне. Дело за автоматизированной проверкой. А автоматизированная проверкаа она не знает о решениях разработчика про правильную последовательность. И ей остается строить граф и искать петли, что дорого и непродуктивно (результаты анализа нужны сейчас, а не как стрясется дедлок). Значит — надо маркировать синкруты в коде в соответствии с определенным разработчиком порядком правильным порядком захвата. Проще всего — указать level.

Итого, граф с петлями развязал разработчик мысленным усилием. Строить его не нужно, искать петли не нужно, остается лишь проконтроллировать правильность порядка (не давать уменьшать уровень, или увеличивать, в зависимости от того, какое направление уровней задано). Лучше всего, если проверка будет выполняться в compile или около того time-е. Но вот чисто не срослось. Раз у меня уже была вкорячена проверка времени выполнения (петель графов), решено было допилить ее. Точнее, перепилить, т.к. графы больше не нужны.

Пара слов о реализации
синкрут — абстрактный класс с методом получения уровня. Почему абстрактный — у меня их много, раздувать память под хранение поля было дорого. А расходы на косвенность через vtbl — не очень.
[ThreadStatic] поле, указывающее на тредконтекст — экземпляр класса, где определен стек взятых синкрутов (односвязный неизменяемый список {next, value}). А на самом деле вместе с синкрутом в списке на каждый узел хранятся sourceLine, sourcePath, memberName, которые подставляет компилятор). Но они не особо нужны.
При захвате читаем [ThreadStatic], определяем последний взятый синкрут (на вершине стека), сравниваем его уровень с уровнем того, который хотим взять. Если равны — пробегаем по стеку взятых рутов с проверкой, а нет ли среди них того, который хотим взять. Это редко на самом деле. И не обязательно, если не поддерживать возможность рекурсивного захвата. Если все плохо — исключение, иначе пушим в стек новый рут и вызываем родной Monitor.Enter. При выходе обязательно проверить что выходим из того рута, который брали последним, выпихиваем его из стека.
Основные накладные расходы в рантайме — чтение [ThreadStatic] и иногда запись в него (один раз на тред). Поддержаны методы Enter/Exit, Wait/Pulse, была когда-то поддержка блокировок, скомбинированными с ReaderWriterLock/Slim; добавлена проверка с помощью using того, что выход из лока произведен тем же тредом, который входил (актуально из-за возможности await внутри using-а async методов).


И теперь вопросы к Sinix.

Re[3]: секунда WTF (lock)
От: Sinix  
Дата: 30.01.17 10:46
Оценка:
Здравствуйте, samius, Вы писали:

S>И теперь вопросы к Sinix.

Их лучше мне в ответе задавать Этот пост чисто случайно прочитал.


S>Вот в таком контексте насколько комильфо в неком сфероконическом случае заюзать недокументированне возможности что бы присесть на lock конструкцию?


Ну... я бы даже заморачиваться не стал рассуждениями комильфо-не комильфо. Такой подход не покрывает часть сценариев (wait handle/spinwait/rwlock/blocking collections etc) => надо использовать что-то другое и не тратить время на полурабочий вариант. Я бы использовал инструментирование кода ч/з Fody, т.к. он бесплатен в отличие от того же постшарпа.



S>Нужна ли такая кухня в CodeJam? Я уже предлагал как-то, но боюсь, что был крайне немногословен. Повторюсь, в каждом проекте оно не нужно. Но и в CodeJam уже дофига экзотики.


Как отдельный проект — безусловно интересно
Как часть библиотеки — чой-то я боюсь пользователи нас не поймут. Реакция "подменять всем lock? вы там совсем упоролись?!!" самая мягкая будет.

Хотя... можно добавить в библиотеку класс LockKey c возможностью в конструкторе задавать ссылку на parent и дальше инструментированием кода отслеживать порядок приобретения локов. Но инструментирование должно быть opt-in, понятное дело.
Re[4]: секунда WTF (lock)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 30.01.17 11:11
Оценка:
Здравствуйте, Sinix, Вы писали:

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


S>>И теперь вопросы к Sinix.

S>Их лучше мне в ответе задавать Этот пост чисто случайно прочитал.
Учту


S>>Вот в таком контексте насколько комильфо в неком сфероконическом случае заюзать недокументированне возможности что бы присесть на lock конструкцию?


S>Ну... я бы даже заморачиваться не стал рассуждениями комильфо-не комильфо. Такой подход не покрывает часть сценариев (wait handle/spinwait/rwlock/blocking collections etc) => надо использовать что-то другое и не тратить время на полурабочий вариант. Я бы использовал инструментирование кода ч/з Fody, т.к. он бесплатен в отличие от того же постшарпа.

С rwlock-ами все работало, но это не отменяет что сценариев лишь часть.
Fody — другой уровень решения проблемы. При наличии анализа либо доступа к тому же IL во время компиляции (или исходникам) — лучше анализировать код, а не делать проверки в рантайме. Но опять таки, либо более-менее полное решение, либо смысла в нем не дофига.

S>>Нужна ли такая кухня в CodeJam? Я уже предлагал как-то, но боюсь, что был крайне немногословен. Повторюсь, в каждом проекте оно не нужно. Но и в CodeJam уже дофига экзотики.


S>Как отдельный проект — безусловно интересно

С претензией на полное покрытие сценариев? Очень сомневаюсь по поводу своего участия. Но и возражать против реализации такого проекта не стану.

S>Как часть библиотеки — чой-то я боюсь пользователи нас не поймут. Реакция "подменять всем lock? вы там совсем упоролись?!!" самая мягкая будет.

Это же не принудительно. Пойми, для чего это, потом, нужно ли это конкретно тебе в этом проекте, а потом уж подменять. Но объяснять такое пользователям — не завидую.

S>Хотя... можно добавить в библиотеку класс LockKey c возможностью в конструкторе задавать ссылку на parent и дальше инструментированием кода отслеживать порядок приобретения локов. Но инструментирование должно быть opt-in, понятное дело.

Что бы ссылку на parent задавать, надо его либо хранить в тредконтексте (тогда зачем задавать явно?), либо тащить по стеку.
Re[5]: секунда WTF (lock)
От: Sinix  
Дата: 30.01.17 11:36
Оценка:
Здравствуйте, samius, Вы писали:

S>Fody — другой уровень решения проблемы. При наличии анализа либо доступа к тому же IL во время компиляции (или исходникам) — лучше анализировать код, а не делать проверки в рантайме. Но опять таки, либо более-менее полное решение, либо смысла в нем не дофига.


Не, это перебор уже, кмк. Fody нужен только чтоб добавить вызовы LockTracer.LockTaken(lockObj) / LockTracer.LockReleased(lockObj) (имена условные) к всем блокировкам, остальное не будет ничем отличаться от текущего варианта с перехватом через "хак" компилятора. Вся разница — надёжней и больше сценариев покрывается.

Про анализ il кода — сами топите урановые ломы в кипящей ртути


S>>Как отдельный проект — безусловно интересно

S>С претензией на полное покрытие сценариев? Очень сомневаюсь по поводу своего участия. Но и возражать против реализации такого проекта не стану.
Ну... тут уж как пойдёт. Даж неполное будет лучше, чем ничего.


S>>Как часть библиотеки — чой-то я боюсь пользователи нас не поймут. Реакция "подменять всем lock? вы там совсем упоролись?!!" самая мягкая будет.

S>Это же не принудительно.
В смысле не принудительно? Подключил библиотеку — получи тип System.Threading.Monitor в подарок. Или мы уже какое-то другое решение обсуждаем?


S>>Хотя... можно добавить в библиотеку класс LockKey c возможностью в конструкторе задавать ссылку на parent и дальше инструментированием кода отслеживать порядок приобретения локов. Но инструментирование должно быть opt-in, понятное дело.

S>Что бы ссылку на parent задавать, надо его либо хранить в тредконтексте (тогда зачем задавать явно?), либо тащить по стеку.
Не, задавать в момент создания, аля
pulic static readonly LockKey RootLockKey = new LockKey("Root");
pulic static readonly LockKey L2LockKey = new LockKey(RootLockKey, "L2");
Re[11]: секунда WTF (lock)
От: Sharov Россия  
Дата: 30.01.17 11:51
Оценка: 2 (1)
Здравствуйте, Sinix, Вы писали:

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


S>>Что именно? Сопровождение не срослось?

S>Ну да — все проекты, что перечислил выше умерли. Даже опенсорсный CHESS — не нужныи оно никому оказалось.

Потому что для серьезных продуктов инструмент уже придуман -- https://en.wikipedia.org/wiki/TLA%2B#Industry_use (TLA+).
Отсутствие спроса на подобные инструменты/анализаторы для дотнет говорит не в пользу платформы.
Кодом людям нужно помогать!
Re[6]: секунда WTF (lock)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 30.01.17 12:03
Оценка:
Здравствуйте, Sinix, Вы писали:

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


S>Не, это перебор уже, кмк. Fody нужен только чтоб добавить вызовы LockTracer.LockTaken(lockObj) / LockTracer.LockReleased(lockObj) (имена условные) к всем блокировкам, остальное не будет ничем отличаться от текущего варианта с перехватом через "хак" компилятора. Вся разница — надёжней и больше сценариев покрывается.

За счет чего более полное-то? Просто убирается хак и только лишь.

S>Про анализ il кода — сами топите урановые ломы в кипящей ртути

Ненуачо, я не подразумевал себя, чисто как идею.


S>>>Как отдельный проект — безусловно интересно

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


S>>>Как часть библиотеки — чой-то я боюсь пользователи нас не поймут. Реакция "подменять всем lock? вы там совсем упоролись?!!" самая мягкая будет.

S>>Это же не принудительно.
S>В смысле не принудительно? Подключил библиотеку — получи тип System.Threading.Monitor в подарок. Или мы уже какое-то другое решение обсуждаем?
Подключил — получи Monitor — абсолютно не вариант. Я такое не предлагал. Я спросил про хак, и отдельным вопросом — надо ли вообще такой инструмент. А уж если надо, то можно было бы обсудить форму и подачу. Но без принудиловки. Т.е. если это бы был хак, то только путем того что пользователь собственной рукой вставляет в свой проект Monitor, но не подключил — получи.

S>>>Хотя... можно добавить в библиотеку класс LockKey c возможностью в конструкторе задавать ссылку на parent и дальше инструментированием кода отслеживать порядок приобретения локов. Но инструментирование должно быть opt-in, понятное дело.

S>>Что бы ссылку на parent задавать, надо его либо хранить в тредконтексте (тогда зачем задавать явно?), либо тащить по стеку.
S>Не, задавать в момент создания, аля
S>
S>pulic static readonly LockKey RootLockKey = new LockKey("Root");
S>pulic static readonly LockKey L2LockKey = new LockKey(RootLockKey, "L2");
S>

Не, тут либо я что-то не понял, либо теряется часть сценариев. Не нужно требовать что бы перед локом таким-то обязательно был взят такой-то. Это более сильное требование, чем необходимо. Если можно взять b после a, то можно взять b и без a, но если взял b — не бери a. Это делает родителей необязательными.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.