Здравствуйте, Sinix, Вы писали:
F>> PS: А Dictionary — зачем там? S>http://stackoverflow.com/questions/3366376/are-net-switch-statements-hashed-or-indexed
Понял. То ли не знал, то ли забыл... Но рослин так не делает. Вместо этого он считает хэш строки, и генерирует код который сравнивает хэши. Начинает так делать он только если есть как минимум 7 кейсов.
Здравствуйте, 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 у него все же стоит? Нет?
Вообще, чего я оправдываюсь? Я не чувствую что набедокурил.
/// <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;
}
Здравствуйте, 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>Вообще, чего я оправдываюсь? Я не чувствую что набедокурил.
В смысле оправдываешься? Мы вроде опытом делимся, а не спорим
Здравствуйте, romangr, Вы писали:
R>А вообще кто-нибудь знает, зачем сделали возможность делать lock на произвольном объекте? R>Сделали бы только Monitor и все только с его экземплярами?
Содрали с жабы не включая моск.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, samius, Вы писали:
S>Вообще, чего я оправдываюсь? Я не чувствую что набедокурил.
А есть ли у вас возможность просто собирать дампы на клиенте? Ну чтобы если лок висит больше какого-то разумного времени, то убивать процесс целиком и снимать дамп с помощью Windows Error Reporting
Здравствуйте, 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>В смысле оправдываешься? Мы вроде опытом делимся, а не спорим
А ощущение что меня сейчас накажут если не отверчусь
Здравствуйте, Слава, Вы писали:
С>Здравствуйте, samius, Вы писали:
S>>Вообще, чего я оправдываюсь? Я не чувствую что набедокурил.
С>А есть ли у вас возможность просто собирать дампы на клиенте? Ну чтобы если лок висит больше какого-то разумного времени, то убивать процесс целиком и снимать дамп с помощью Windows Error Reporting
Нету такой возможности.
Здравствуйте, samius, Вы писали:
S>Что именно? Сопровождение не срослось?
Ну да — все проекты, что перечислил выше умерли. Даже опенсорсный CHESS — не нужныи оно никому оказалось.
S>Мой оптимизм с инструментальным контролем проверки уровня немного оптимистичнее твоего без онного.
Есть такое дело Точнее, я рассчитываю на то, что если при написании кода нет блокирующих ожиданий и петель, то и о дедлоках заботиться незачем. Ну, а если чего вдруг и проскользнёт — то они обломится на await с timeout-ами и этого будет достаточно для диагностики. Пока что этот подход не подводил, смысла дёргаться не вижу
S>Что бы проверять петли графа — его надо строить (в рантайме), делать проверку на петлю при каждой попытке блокировки, достраивать ребро при удачном захвате, удалять при выходе из лока. S>А уровень проверяется одним сравнением целого с целым. Если не считать обращение к [ThreadStatic] полю.
Ну тут всё от доверия к коду зависит. Для произвольного кода только проверки на уровень иерархии лока недостаточно, как по мне.
S>CPS — это continuation-ы? Таски? Не всегда это выгоднее.
О, а давай пример тогда Хоть какой. А то у меня пока в основном обратные примеры копятся — без сложных локов проще.
S>А ощущение что меня сейчас накажут если не отверчусь
Упс
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Что именно? Сопровождение не срослось? S>Ну да — все проекты, что перечислил выше умерли. Даже опенсорсный CHESS — не нужныи оно никому оказалось.
Ок, понял.
S>>Мой оптимизм с инструментальным контролем проверки уровня немного оптимистичнее твоего без онного. S>Есть такое дело Точнее, я рассчитываю на то, что если при написании кода нет блокирующих ожиданий и петель, то и о дедлоках заботиться незачем. Ну, а если чего вдруг и проскользнёт — то они обломится на await с timeout-ами и этого будет достаточно для диагностики. Пока что этот подход не подводил, смысла дёргаться не вижу
Конечно незачем если при написании нет блокирующих ожиданий. А вот у меня проект чуть ли не весь из блокирующих ожиданий. А что бы не было петель — контроль.
S>>А уровень проверяется одним сравнением целого с целым. Если не считать обращение к [ThreadStatic] полю.
S>Ну тут всё от доверия к коду зависит. Для произвольного кода только проверки на уровень иерархии лока недостаточно, как по мне.
Хорошо, а чего будет достаточно?
S>>CPS — это continuation-ы? Таски? Не всегда это выгоднее. S>О, а давай пример тогда Хоть какой. А то у меня пока в основном обратные примеры копятся — без сложных локов проще.
Дык я не спорю что без них проще.
Текущий проект, над которым работаю — сервис, обслуживающий коллбэки из драйвера файловой системы. Типа смарткэша для облачного файлового хранилища (корпоративного, не личного).
Блокировками (в том числе) защищена единая модель дерева файлов в памяти. В следующей версии мне дали добро на переход к модели, построенной по функциональным принципам (на неизменяемых данных), что бы уйти от блокировок при обращении к модели. Но модель дерева файлов — не единственное, что требует блокировок.
Здравствуйте, samius, Вы писали:
S>>Ну тут всё от доверия к коду зависит. Для произвольного кода только проверки на уровень иерархии лока недостаточно, как по мне. S>Хорошо, а чего будет достаточно?
Ну как минимум — отслеживание всех блокирующих вызовов (их не так уж и много). Иначе будут неловящиеся дедлоки, пример уже подкидывал. В идеале — ещё и трассировку async-callback-ов добавить, через async local. Но это уже по желанию.
S>Текущий проект, над которым работаю — сервис, обслуживающий коллбэки из драйвера файловой системы. Типа смарткэша для облачного файлового хранилища (корпоративного, не личного). S>Блокировками (в том числе) защищена единая модель дерева файлов в памяти.
А. Мы такое когда-то делали на очередях и cqrs-style (хотя тогда cqrs ещё в моде вроде не был... что-то подобное короч) уведомлениях об изменении данных. Но у нас не было требования консистентности, т.е. модель в памяти могла отражать содержимое файлов с некоторой задержкой. Ну, и данные делились так, чтобы отдельные части можно было безопасно обновлять параллельно, каждая часть обрабатывалась в один поток. В общем, 9/10 всех костылей было убрано ещё в момент проектирования и работать было сплошным удовольствием.
Если требование консистентности есть — то да, жизнь становится заметно интереснее
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Хорошо, а чего будет достаточно? S>Ну как минимум — отслеживание всех блокирующих вызовов (их не так уж и много). Иначе будут неловящиеся дедлоки, пример уже подкидывал. В идеале — ещё и трассировку async-callback-ов добавить, через async local. Но это уже по желанию.
Да, при обращении к блокирующим асинхронным вызовам (например, сервера) могу потребовать отсутствия захватов у вызывающего потока, раз я их (захваты) отслеживаю.
Хорошая мысль, спасибо. Хоть это требование должно быть не забыто добавлено в код руками, оно просигналит что блокирующий код вызван из под lock-а.
S>>Текущий проект, над которым работаю — сервис, обслуживающий коллбэки из драйвера файловой системы. Типа смарткэша для облачного файлового хранилища (корпоративного, не личного). S>>Блокировками (в том числе) защищена единая модель дерева файлов в памяти.
S>А. Мы такое когда-то делали на очередях и cqrs-style (хотя тогда cqrs ещё в моде вроде не был... что-то подобное короч) уведомлениях об изменении данных. Но у нас не было требования консистентности, т.е. модель в памяти могла отражать содержимое файлов с некоторой задержкой. Ну, и данные делились так, чтобы отдельные части можно было безопасно обновлять параллельно, каждая часть обрабатывалась в один поток. В общем, 9/10 всех костылей было убрано ещё в момент проектирования и работать было сплошным удовольствием.
S>Если требование консистентности есть — то да, жизнь становится заметно интереснее
Хм, навскидку сложно сказать, может ли драйвер файловой системы теоретически работать с cqrs, все-таки какие-то гарантии требует и сам Windows при обращении к драйверу. Создание файла подразумевает возврат хэндла созданного файла, что вроде бы уже выпадает из cqrs. Можно ли там схитрить — фиг знает.
Возможно ли такое, что ты сврй подход щаоаенсорсишь и сделаешь нормальное объяснение как этим пользоваться?
Смотри — первый бенефит — оно нафиг никому не надо.
Второй бенефит — ты потратишь время впустую.
Механизм используемый тобой слишком слоден доя новичков имхо, но, имхо, на самом деле — твоя практика тут... бесценна. Ты ж ведь из тех кто юзает дотнет почти сгачала если я не ошибаюсь, а вае "знакомство" с Sinix волей судеб случилось токс щас? Хотя это дико — я давно ставлб оценки тока ему и рслн меня режет за межуусобничество — но я его в глаза не знаю...
А и пофиг. Мне всегда на них было пофиг.
Просто если есть реально хорошмй опыт — имхо — его стоит описать, тем более если есть примеры.
Безусловно — нужно твоё желание, нужно вообще видение этого как статьи. Я лично доя себя понял что вы межлу собой поговорили о чем-то. Не то. Ну не то что-бы у мну фантазия не работала, но это другое.
@samius, если ты готов поделиться опытом — я думаю как минимум это оценят даже "смежники", вдобавок задача что ты озвучил — два раза как выбивается в интересные — она ведь из области того запрещённого кода где некоторые считаю что никто кроме... (неважне чего — важен факт).
Мне кажется если иы осилишь аггрегировать свой опыт — это было бы интересно.
Нафуя? Х.з.
Здравствуйте, 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 (именно той, что в старте топика) для диагностики дедлоков. Статью я уже искал ранее, вот и сейчас не нашел. Там именно что при попытке захвата проверялся граф уже захваченных локов, который при удачном захвате достраивался (через захват глобального синкрута). Это все работало только для дедлоков вида
с поправкой на неопределенную глубину вложений. И при обнаружении дедлока в момент захвата сразу кидается исключение (со стеком и шлюхами). Все круто, исключение вместо зависания — это определенно прогресс. Но дедлок — это такая история, которая может то ли случиться, то ли нет, то ли в этом году, то ли в следующем, то ли на машине разработчика, то ли у юзера, который то ли забьет, то ли нет. На счет этого статья более ничего не предлагала. Тогда я статью почитал и забыл. Больше ее не видел.
История продолжилась пару лет назад, когда в бете текущего проекта искали злой дедлок, который просто вымораживал винду на машинах пользователей. Вспомнил я про ту статью, накидал подобную диагностику, заменил все 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.
Вот в таком контексте насколько комильфо в неком сфероконическом случае заюзать недокументированне возможности что бы присесть на lock конструкцию? В текущем проекте посовещались, решили не заморачиваться и оставить using-и.
Нужна ли такая кухня в CodeJam? Я уже предлагал как-то, но боюсь, что был крайне немногословен. Повторюсь, в каждом проекте оно не нужно. Но и в CodeJam уже дофига экзотики.
Здравствуйте, samius, Вы писали:
S>И теперь вопросы к Sinix.
Их лучше мне в ответе задавать Этот пост чисто случайно прочитал.
S>Вот в таком контексте насколько комильфо в неком сфероконическом случае заюзать недокументированне возможности что бы присесть на lock конструкцию?
Ну... я бы даже заморачиваться не стал рассуждениями комильфо-не комильфо. Такой подход не покрывает часть сценариев (wait handle/spinwait/rwlock/blocking collections etc) => надо использовать что-то другое и не тратить время на полурабочий вариант. Я бы использовал инструментирование кода ч/з Fody, т.к. он бесплатен в отличие от того же постшарпа.
S>Нужна ли такая кухня в CodeJam? Я уже предлагал как-то, но боюсь, что был крайне немногословен. Повторюсь, в каждом проекте оно не нужно. Но и в CodeJam уже дофига экзотики.
Как отдельный проект — безусловно интересно
Как часть библиотеки — чой-то я боюсь пользователи нас не поймут. Реакция "подменять всем lock? вы там совсем упоролись?!!" самая мягкая будет.
Хотя... можно добавить в библиотеку класс LockKey c возможностью в конструкторе задавать ссылку на parent и дальше инструментированием кода отслеживать порядок приобретения локов. Но инструментирование должно быть opt-in, понятное дело.
Здравствуйте, 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 задавать, надо его либо хранить в тредконтексте (тогда зачем задавать явно?), либо тащить по стеку.
Здравствуйте, 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");
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Что именно? Сопровождение не срослось? S>Ну да — все проекты, что перечислил выше умерли. Даже опенсорсный CHESS — не нужныи оно никому оказалось.
Потому что для серьезных продуктов инструмент уже придуман -- https://en.wikipedia.org/wiki/TLA%2B#Industry_use (TLA+).
Отсутствие спроса на подобные инструменты/анализаторы для дотнет говорит не в пользу платформы.
Здравствуйте, 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. Это делает родителей необязательными.