« first day (984 days earlier)      last day (2047 days later) » 

7:21 AM
@VladD ну для тех кто использует исключительно lock можно сказать что она одна )
 
 
9 hours later…
4:35 PM
@vitidev, @VladD, если будет полезно, вот этот чувак нормально о модели памяти рассказывает. Правда там C++
 
 
4 hours later…
8:16 PM
@Bretbas Спасибо! Но это модель памяти C++, она сильно отличается от модели памяти C#.
@vitidev Модель памяти устанавливается стандартом языка. Поведение программы, нарушающей условия этой модели памяти (наподобие несинхронизированного доступа к переменным) является по большому счёту UB, и в корне противоречит духу C#.
У языка нету «модели памяти на процессоре X», у языка есть одна единственная модель памяти.
 
8:35 PM
@VladD ага ага. вот только все хорошо только в мире локов.
 
@vitidev Нету «мира локов». Есть мир следования спеке, и мир UB, полный боли и страданий.
Вы, наверное, не так долго писали на С++. Там вот отступление от спеки очень быстро и больно карается компилятором.
(Причём карается не вылетом, это было бы небольно, а наоборот необъяснимым поведением вроде бы правильного кода вдалеке от точки нарушения.)
 
@VladD а если спека не осыещает нужные вопросы. аж никак вообще
 
@vitidev Значит, не надо так делать, как не описано в спеке.
Ну или делайте, кто ж вам запретит. Но только ответственность за результаты лежит сами знаете на ком.
 
@VladD то есть не писать локфри код вообще? но ведь сам дотнет состоит из локфри кода.
 
@vitidev А его разрабатывают те люди, которые спеку писали. Им можно.
Я не чувствую себя настолько крутым.
 
8:41 PM
те люди говорят что "мы не можем знать как будет развиваться железо"
в частности именно поэтому волатиле зло...но без волатиле не обойтись. вот такие пиржоки
 
Вы не можете добиться правильного результата, просто скопировав чужой приём. Нужно в точности понимать, что и при каких условиях можно, а что нельзя.
@vitidev Я всегда обходился без него.
Так что в «не обойтись» не верю
 
дело не в крутости, а в том что нужные вопросы просто не освещены в спеке, а раз не освещены то на свой страх и риск
вот только процессоры они материальные и на них писать надо
вы не можете напистаь локфри код без барьеров и волатиле. аж никак
 
@vitidev Не надо писать код под процессор. Вы не разработчик JIT-компилятора. Пишите код под спеку.
@vitidev А я и не пытаюсь.
 
повторюсь. спека НЕ освещает эти вопросы
@VladD а зачем спорите тогда
 
Оптимизации производительности достигаются вдумчивым переписыванием архитектуры.
 
8:44 PM
я говорю о базовых вещах а не о архитектуре
какая архитектура у конкурентсловаря? никакой. это другое вообще
вы как то однобоко смотрите на вещи
вы пишете приложения. но кто то же пишет другие вещи. например даже драйвера. но почему вы считаете что все пишут только то что и вы
 
@vitidev Я не спорю. Я говорю, что вы пытаетесь заткнуть отсутствие разумной архитектуры в проекте низкоуровневыми трюками. Это плохо со всех сторон.
Во-первых, это не скалируется.
Ну достигнете вы ускорения вдвое, и что?
Придёт вдвое больше клиентов
Во-вторых, это приводит к неподдерживаемому коду
 
как вы думаете откуда бы взялись разработчики локрфи вещей если бы все думали как вы )))
 
Если в проекте, к примеру, вместо Dictionary используется линейный список, то какие трюки не применяй, будет тормозить
Локфри или нет, не важно
Локфри нужен в том редком случае, когда алгоритмика идеально вылизана
 
перестаньте прошу вас судить с позиции написания приложений. потому что я не тяну локфри в приложения
 
Мне сильно кажется, что у вас XY Problem.
 
8:48 PM
нет. у меня просто хобби. вы пишете что то и дальше не лезете. мне же интересно и другое - например локфри. а почему нет? или вы думаете что те люди что пишут локрфи - их заставляют что ли? видимо вы так и думаете
я и свои компиляторы писал. а почему нет. это скил. это интересно
вам не нужно, но блин не судите всех по себе.
 
И давайте не будет презрительно отзываться о приложениях. У меня в коде есть нагруженные куски, и я справлялся в проблемами, улучшив алгоритмы. Это ускорило вычисления раз в 20.
Да, в нескольких местах пришлось отказаться от виртуальных функций и что-то после тщательного профилирования заинлайнить руками, это принесло ещё 10% производительности.
 
я отзываюсь о вашей позиции "оно вам не надо". потому что она ошибочна.
 
Вы описываете архитектуру, которую можно сильно улучшить. Я всё ещё считаю, что вы ищете производительность не там, где потеряли
Модель памяти описана довольно бедно, и официальное описание недостаточно.
 
@VladD архитектура то что я делал и лок фри вообще не связаны. я говорил про волатиле как флаг для сборки мусора что для ЭТОЙ задачи даже если нет лока то нормально аж более чем
 
Поэтому можно считать, что в C# низкоуровневые трюки не одобрены разработчиками языка.
 
8:53 PM
мне локфри интересен просто как локфри
я не говорю про стакалллок. я говорю про спеку и реальность.
и кстати одобрены )) с чего вы взяли что не одобрены
 
@vitidev Тем, что в спеке нет хорошо выписанной подробной модели памяти
В отличие, кстати, от Джавы, которую я за всё остальное сильно недолюбливаю
 
про LOH разрабы языка пишут что не чурайтесь оптимзаций в виде чункования списков если надо. Это не типичная задача, но не чудо невиданное. то есть они понимают.
 
@vitidev Разрабы?
Я пока видел это только в какой-то статье на Хабре
 
угу нету. потому я и пытаюсь разобраться. чтобы знать реальную суть вещей. а почему нет. любопытство не порок
когда буду "преждевременно оптимизировать" тогда и приходите.
 
Но да, как микрокостыль покатит
@vitidev Если спеки нет, «разобраться» нельзя. Вы можете случайно узнать текущее неспецифицированное поведение компилятора, но поскольку оно неспицифицировано, то опираться на него нет никакого смысла — оно не гарантировано
Опираться можно только на то, что обещано
То есть на действующую спеку
 
8:59 PM
это и есть "разобраться". это и есть понять что не так с волатиле, но при этом все в порядке с барьерами. при том что волатиле....те же барьеры

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

а если вдруг таки надо писать локфри то как это правильнее делать с такой то спекой.
 
@vitidev Это не называется «разобраться»
 
я люблю интересные вопросы и люблю знать на них ответы
вот один из них https://stackoverflow.com/questions/16162745/event-raising-and-read-introduction-in-net-4-5
 
Неспецифицированное поведение компилятора имеет право поменяться в любую секунду
 
@VladD не хочу спорить. полагаю вы не понимаете смысла этого слова.
ну вот посмотрите по ссылке )))
 
@vitidev Ну да, неспецифицированное поведение.
Посмотрел
 
A K
9:02 PM
@vitidev кажется, вы путаете хакеров и разработчиков.
 
Спеки нет
 
кажется вы путаете ремесленников разрабов и разрабов для которых это еще и хобби. первые пишут только то что надо. другие пишут компиляторы, локфри структуры, локфри алгоритмы и много много чего еще, пишут статьи а так далее

я отношусь ко вторым. хакинг тут не причем вообще. даже если я не буду писать в продакшене никогда я не могу просто забыть о вопросе " а че так то" и буду искать ответ
 
@AK C++ в своё время стал очень сильно наказывать «хакеров», которые «разобрались», какой код генерирует обращение по указателю, и пытались вызывать нестатические методы по нулевому указателю.
 
липерт скзал про волатиле но толкмо не пояснил. мне стало интересно. вам нет - вот между нами разница. вы пытаетесь навязать мне "оно вам не надо"
а я пытаюсь поянсить "оно мне интересно и я хочу знать глубже"
 
если метод не обращается к полям, говорили они, то компилятор не будет разыменовывать this, и значит, можно писать код, который по спеке UB
 
A K
9:08 PM
вы проводите разницу по линии любопытно vs не любопытно. В то время как вопрос в том, опираться использовать в продакшене или не использовать.
 
потом пришёл оптимизирующий компилятор, увидел, что в коде UB, и радостно воспользовался этим для оптимизации, выбросив этот код
 
@AK но это ваш вопрос. не мой. это вы тянете эту линию поведения в разговор
мой вопрос былв том "почему липерт так сказал, что это значит. как это понять то"
даже по ссылке смотрите затык - с одной стороны рекомендованный паттерн, с другой стороны его вполне может заоптимизить. Вы скажете "локи спасут всех". Но разве спасут? вы помню говорили что нельзя из лока вызвать событие. значит лок пролетает

ваш Engine тоже не катит. в него можно войти в хендлене а нам надо в вызове. К тому же даже он не спасет.
и когда нибудь в теории будет бум-с и у вас. хотя вы все "правильно" кодите с вашей позиции. Мне такие моменты интересны. мне все интересно. если я не знаю ответа я плохо сплю
 
@vitidev (Относительно) потокобезопасный паттерн отправления события такой:
EventHandler copy;
lock(mutex) copy = OnClick;
if (copy != null) copy();
сейчас гарантировано MSDN'ом потокобезопасность такого:
OnClick?.Invoke()
> ваш Engine тоже не катит. в него можно войти в хендлене а нам надо в вызове. К тому же даже он не спасет.
 
ну это вы перегнули. достаточно барьера. вариант с ?. мы не должны рассматривать. старый код может быть сто лет назад скомпилен.
 
Вот здесь, признаться, ничего не понял
@vitidev А где написано, что достаточно?
 
9:18 PM
@VladD ENgine не контролирует точку вызова события. Потому что на событие могут быть подписано много кого и у каждого может быть свйо Engine. И в любом случае не контролит сразу обе точки - подписку и вызов
 
@vitidev Вы о моём Engine?
 
в спеке. барьер защитит от оптимизации jit
ага о вашей
 
Тогда о каком событии идёт речь?
@vitidev А где написано, что проблема только в оптимизации jit?
 
нужно понимать что ?. это просто сахар и на уровне байткода одно и то же.
 
В спеке должно быть написано, это thread safe или нет
 
9:20 PM
начиная Read Introduction As I just explained, the compiler sometimes fuses multiple reads into one.
 
@vitidev Не нужно понимать. Есть гарантия на ?., а на другой путь вызова такой гарантии нет
 
впрочем вы правы. кто угодно может запомтизировать. и компилятор и jit могут учудить. про компилятор вот описано. а jit - их щас развелось
 
Вы не знаете, какой special case'инг есть у jit
И я не знаю
Возможно, они завтра встроят дополнительную оптимизацию
 
вы не поняли сути. вы прочли про такую оптимизацию и вам без разницы "а как же работает вызов события в старом стиле то а". а мне интересно и тому человеку что задал вопрос интересно
 
а случай ?. будут обрабатывать особо
@vitidev В старом стиле не было гарантии
То есть была, но только с lock'ом
 
9:22 PM
@VladD не стоит на него надеяться. я могу получить с репы код в октором не было никаких ?. и я не буду его переписывать а просто буду компилить
 
@vitidev Можете. Но без lock'а он будет непотокобезопасен
 
а вызывать события в lock плохо по вашим же словам. )
 
@vitidev Да, конечно. Я привёл правильный паттерн
EventHandler copy;
lock(mutex) copy = OnClick;
if (copy != null) copy();
 
и вообще когда автор кода писал свой код у него не было проблем ведь на тот момент это был рекомендованный паттерн. да он до сих пор в мсдн
и зачем тут lock
 
@vitidev Это вы о каком паттерне?
 
9:25 PM
все о том же
void RaiseEvent()
{
var myEvent = MyEvent;
if (myEvent != null)
{
myEvent(this, EventArgs.Empty);
}
}
 
А, да, это непотокобезопасно
и всегда было так
 
но он до сих пор тут
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-publish-events-that-conform-to-net-framework-guidelines
и все таки. зачем там lock
 
@vitidev Да, разумеется. По умолчанию даётся непотокобезопасный паттерн
Точно так же практически все примеры с List<T> непотокобезопасны
@vitidev Потому что мы обращаемся к разделяемой переменной. Это нужно делать под lock'ом
 
стоп. он вполне потокобезопасный. если компилятор его не портит. комплиятор его не портит, поэтому все у всех прекрасно работает.
а там LIst что ли
 
@vitidev Это неверно, он непотокобезопасный
 
9:28 PM
@VladD дык вы просто ее копируете под локом. в этом нет смысла
 
Чтение разделяемой переменной без синхронизации никогда не было потокобезопасным
 
@VladD ссылки?
 
@vitidev Спека в вашем каталоге с Visual Studio
@vitidev Вы серьёзно?
То есть вы и правда не понимаете, для чего там локальная переменная и lock?
Локальная переменная не является разделяемой, а значит, к ней можно обращаться без синхронизации
А обращение к разделяемой переменной происходит под локом
 
1) чтение ссылки атомарно (так грит спека)
2) вы под лок пихаете только чтение самой ссылки, а не какую то работу в критической секции (вы ниже работаете просто с копией)
 
@vitidev Ну и что?
Атомарно != потокобезопасно
Чтение инта тоже атомарно
 
9:32 PM
а то что смысла в локе нет. и без лока по спеке чтение будет атомарным и будет создана копия ссылки. вы же всего лишь копируете ссылку а не сам обьект
 
@vitidev Атомарно != потокобезопасно
 
сможете привести кейс?
 
@vitidev да пожалуйста
static int x;
while (x == 0) { } // один поток
x = 1; // другой поток
при определённых условиях джиттер понимает, что x не меняется в потоке, и не перечитывает его
не всегда
типичное UB
 
это int. это не ссылочный тип. а там мультикастделегат который ссылочный. и вы под локом делаете просто копию ссылки оправдывая это потокобезопаснотью (что в данном контексте не пойму о чем вы)
а "оптимизацию джита или компилятора" мы обходим. ее просто заткнуть барьером хотя и этого не нужно на текущий момент

так что я хочу кейс когда 2 потока без лока работают иначе чем с локом в этом месте. я такой кейс придумать не могу
чет я не то сказал
ну суть прежняя. забыли про джит
заткнуть джит может и барьер. зачем там аж целый лок
тем более вы сказали что лок не для джита а из за потокобезопасности
 
@vitidev Вы просили контрпример против того, что атомарно == потокобезоопасно. Я его привёл. С этого момента давайте не будем считать, что атомарно == потокобезопасно.
@vitidev Ссылочный тип или нет, не важно. Важно то, что атомарности недостаточно
 
9:38 PM
смотрите. на текущий момент паттерн без лок и с лок работают абсолютно одинаково в силу того что оптимизация не происходит. ваша позиция какая?
1 нельзя надеятся на щас - потом может быть иначе
2 оптимизация не причем - лок тут для другого

ваш вариант 1 или 2?
 
@vitidev Вы о каком паттерне?
С ?. или без?
 
все то же. мы говорим о вызове события без ?.
 
@vitidev Он непотокобезопасен
«Работает абсолютно одинаково» — нет
 
поясните как ВАШ лок в ЭТОМ месте меняет ситуацию
 
@vitidev Я читаю разделяемую переменную под локом
разделяемой переменной является ссылка на MulticastDelegate
Код без лока читает разделяемую переменную без лока
соответственно он непотокобезопасен
Сам по себе MulticastDelegate является иммутабельным, и поэтому синхронизировать обращения к нему не нужно
только чтение ссылки
 
9:41 PM
а в чем проявляется эта непотокобезопасность то? я понять не могу. операция атомарна - ссылка просто копируется полностью и без повреждений хоть без локов хоть с локами

разницы нет
 
@vitidev Чтение ссылки — такое же чтение разделяемой переменной, как и чтение int x из примера
 
в примере вы упомянули джит. волатиле обломает зубы джиту в этом месте если уж мы говорим про оптимизацию джита

вы только про джит или есть еще что то?
в этом месте достаточно барьера
давайте так. забыли про джит. считайте что у нас дебаг сборка без оптимизаций вовсе
разница в паттернах по прежнему есть ?
но лучше пойти спать и уже завтра
 
@vitidev Не, я не говорил про jit
Я имел в виду, что потокобезопасность этой конструкции не гарантирована
а где именно проблемы, в спеке не прописано
 
а я в упор не могу понять в чем смысл лока в этом месте. в обоих случаях результат одинаковый- мы получаем ссылку в локальную переменную и лок не влияет ни на что (кроме джита)
и далее мы с этой локальной переменной уже работаем вообще одинаково
 
поэтому проблемы могут быть в любой точке
@vitidev а в чём смысл лока с любой точке?
с точки зрения компилятора, он имеет право на любую трансформацию кода, лишь бы с точки зрения однопоточного выполнения внешние проявления не менялись
в отсутствие локов
например, он имеет право вообще убрать переменные
если лока нет, он имеет право выкинуть локальную переменную
 
9:56 PM
проблема - когда уже отписались от события но мы захватили переменную и не знаем об этом
но этот лок этй проблемы не решает

смысл лока нужен там где операция не атомарна. чтение 2х переменных не атомарно. прочли первую и наали читать вторую, а первая уже не такая.

копирование ссылки атомарно и никаких последвтий не несет хоть ставь лок хоть нет (джит и комплиятор моы обходим стороной. вы сказали что дело не в нем - и для него хватит барьера и он ничего не тронет)
 
@vitidev смысл лока в том, что внутри него можно обращаться к разделяемой переменной
вот и весь смысл
не, не весь, конечно
но это в текущий точке обсуждения основной
> смысл лока нужен там где операция не атомарна
Этого я не говорил
 
я не понимаю этого выраженя в ДАННОМ контексте. в евенте мы хотим получить снапшот чтобы потом проверить на нулл и никто не обнулил ибо снапшот у нас захвачен в локальной переменной

но для захвата снапшота нам не нужен лок
 
Я говорил, что атомарность вообще нерелевантна
Под локом можно читать разделяемую переменную, компилятор гарантирует отсутствие сюрпризов
А без лока гарантий нет
Компилятор вообще не обязан исполнять код построчно, как написано
 
я скажу прямо. если не брать в расчет джит и комплятор с его оптимизациями, то в данном случае ваш лок вообще не нужен.
 
И не обязан, если вы используете локальную переменную в коде, реально выделять памть на стеке
@vitidev Это имеет смысл только для компиляторов времён Кернигана и Ричи, которые выполняли код построчно
А последние 30 лет компиляторы имеют право на любую трансформацию кода в отсутствие синхронизации
И очень активно этим пользуются
 
10:02 PM
@VladD то есть все в итоге уперлось в "лок нужен чтобы компилятор или джит не намутили" на что я уже ответил "барьер решит этот вопрос"
 
Когда вы говорите о локальной переменной, вы должны понимать, что на уровне скомпилированного кода её может и не быть
@vitidev Вы можете это подтвердить ссылкой на MSDN?
 
@VladD что? что барьер запретит реордер операций компилятору?
 
@vitidev Не знаю. Думаю, что неполный барьер даёт соответственно одностороннюю гарантию. Но это мои предположения. И это лишь гарантия отсутствия перестановки инструкций. А кроме этого компилятор в отсутствие синхронизации имеет право просто выкинуть вашу локальную переменную
Кто сказал, что перестановка инструкций — единственная оптимизация?
 
@VladD ну барьеры разные бывают. барьер запрещает что то делать после барьера пока не сделано перед барьером если барьер запрещает прыжки. потому пока не скопирует, то дальше барьера не пойдет. на то он и барьер
 
Спека не гарантирует, что int-переменная в коде соответствует фиксированной области памяти длиной в 4 байта
Поэтому когда кто-то говорит «в кеше какого процессора находится эта переменная», это выражение лишено смысла. Переменные языка не обязаны мапиться на память.
 
10:08 PM
ну кеш это вообще отдельная песня. я говорю про то что комплятор не выбросит переменную из за барьера.
 
@vitidev Почему это?
Это чем-то гарантировано? Спекой?
 
да. это не реордеринструкций. это указание комппилятору этого не делать.
я не могу найти норм пруф потому что я не знаю как называется этот случай
 
Вот например, у вас есть локальная переменная. Компилятор заинлайнил вашу функцию, и увидел, что он знает точные значения параметров, и теперь маша локальная переменная просто не нужна.
@vitidev Боюсь, потому, что это просто не так
В спеке нету нигде понятия «компилятор» и «джит». В спеке есть только семантика программы.
Если спека что-то гарантирует, то весь тулчейн должен об этом позаботиться
А какие образом оно это делает, нигде не специфицировано
 
ну липперт про конкретно ЭТОТ случай говорит что компилятор вообще не трогает а джит может. и что дижт видя барьер намного менее агрессивно оптимзирует и так то лок, волатиле, барьеры тут подходят
 
То есть я по сути даже не согласен с утверждением о том, что переменная в C# соответствует области памяти. По крайней мере не нашёл этого в спеке
 
10:15 PM
в спеке рыть не хочу. я и спеки найти не могу даже для 4 шарпа
 
@vitidev Он говорит, что есть какая-то гарантия?
Есть гарантия, что барьер поможет?
 
Just because there's a memory barrier does not necessarily mean that read introduction optimizations are not performed. However, the jitter is far less aggressive about pursuing optimizations that affect code that contains a memory barrier.
 
Есть гарантия, что компилятор не будет ничего переставлять?
@vitidev far less aggressive — это ведь вы не считаете гарантией?
 
ну если забыть про арм то на х86-64 проблемы нет как таковой.
я ж говорю арм особняком стоит
 
@vitidev Вы снова говорите о каких-то процессорах
 
10:18 PM
@VladD нуу если джит будет ломать барьеры то такой джит далеко не уедет в продакшене. вряд ли джит когд алибо будет такой что поломает сам фреймворк
 
Они в этом обсуждении пока совсем не при чём
@vitidev Джит имеет право делать всё, что не запрещено спекой
Код в продакшене пишется по спеке
Поэтому он работает
 
вы думаете что сможет резизнуться джит который ломает 90% кода в мире, то есть сам фреймворк?
 
@vitidev Сам фреймворк джит ломать не будет. Ну так джит распознаёт, когда он компилирует фреймворк, и делает какую-то магию
А для кода, который пишем мы, никакой магии от джита не положено
Цель тулчейна — чтобы фреймворк делал обещанное и чтобы код, написанный по спеке, работал правильно
 
барьер по своей природе просит не смешивать до и после. если джит на это плюет то он будет просто ломать код. разрабы джита не настолько тупые чтобы это сделать
 
@vitidev Понятие «до» и «после» можете сформулировать точно?
Вы почему-то считаете, что индустрия делаете такие же грязные трюки с барьерами и volatile. Нет, в индустрии за такое бьют по пальцам.
 
10:24 PM
лучше скажу как в вики (хоть там не про шарп) чтобы не печатать
Барьер памяти (англ. memory barrier, membar, memory fence, fence instruction) — вид барьерной инструкции, которая приказывает компилятору (при генерации инструкций) и центральному процессору (при исполнении инструкций) устанавливать строгую последовательность между обращениями к памяти до и после барьера. Это означает, что все обращения к памяти перед барьером будут гарантированно выполнены до первого обращения к памяти после барьера.
 
Именно потому, что гарантий на это нет
 
@VladD без них локфри не написать. НЕВОЗМОЖНО. без них не написать под арм локфри код НЕВОЗМОЖНО В ПРИНЦИПЕ
 
@vitidev Это правильно. Но это говорит о машинном коде, а не об исходниках на C#. А соответствие между ними очень сильно нелинейное
@vitidev Ну так кому нужен локфри, тот пишет на языках с чёткой моделью памяти, например, на C++
Ну допустим даже, что не написать, и что?
 
@VladD в исходниках тонны волатил. однако в поддержке заявлен и арм
 
@vitidev Ещё раз. Исходники для вас не пример, их джит компилирует по-своему.
И там разработчики знают точно, какая семантика volatile
А мы с вами нет
 
10:28 PM
@VladD по какому по своему? с чего вдругособое отношение
 
И если у них поменяется jit, они подправят фреймворк
@vitidev А почему нет?
Как вы думаете, скомпилирует такое компилятор в обычном режиме?
Нельзя подглядывать в исходники фреймворка. Они используют там всякие вещи, но они умеют это делать и точно знают, какие гарантии им это даёт.
А поскольку эти гарантии не отображены в спеке, то надеяться (а) угадать эти гарантии без документации, и (2) рассчитывать на них выглядит весьма самонадеянно
 
в спеке вообще мало что есть.
ну разве что вот https://stackoverflow.com/questions/5816939/are-reference-assignment-and-reading-atomic-operations

как я понял тот же вопрос и там чел на спеку ссылается
но блин где сама спека я не знаю
там все таки про процессор а не про джит
 
@vitidev Ну, bad luck — то, чего спека не гарантирует, то не гарантровано
@vitidev Ну там сказано «reference assignment/reading is guaranteed to be atomic»
 
10:43 PM
спека и про таски не говорит что они барьеры содержат. но вы же не ставите барьеры после них )
 
А мы уже выяснили, что atomic — это слабенькая гарантия
 
хотя тпл это более либа чем язык
 
@vitidev Угу, вот этот вопрос я хотел задать тоже
как с точки зрения спеки выглядит код
async Task T()
{
    int a = 1;
    await Task.Yield();
    Console.WriteLine(a);
}
что именно гарантирует возможность обращаться к a без синхронизации
пока это пробел в моих знаниях
причём задать не на SO
а на гитхабе разработчикам языка
 
вы торопитесь. этот момент я хотел обсудить следующим после разбора с евентами, вернее это пункт 3
 
@vitidev Ну с ивентами-то мне всё понятно
а вот с async/await нет
 
10:49 PM
ну тоуб сказал что на гразнице тасков юзаются барьеры. получается у вас после а=1 сразу идет барьер
 
@vitidev Ну это он сказал, а я хочу, чтобы (1) сказала спека, и (2) не в терминах барьеров, а в терминах гарантий
 
барьер это гарантия неперестановки операций чтения и записи. тут у вас и запись и чтение
 
@vitidev не-не. мы уже выясняли, что текст на C# не мапится однозначно на инструкции процессора с сохранением порядка
 
а причем тут это. перед барьером и после он может перемешивать как хочет. а между барьерами порядок не сдвинет. в этом суть барьеров
 
Что именно перемешивать?
 
10:53 PM
int a = 1;
int b=2;
await Task.Yield();
Console.WriteLine(a);

а и б может пеставлять сколько угодно. но ни одна из них не опустится ниже await
 
@vitidev Почему?
 
@VladD что значит почему? в этом суть барьеров чтобы защищать от таких вот переползаний куда не надо. они для этого и придуманы
тут конечно все сложнее ибо await развернется в невесть что. но там будут барьеры которые отгородят
 
@vitidev Ну можно какую-то ссылку на это?
 
@VladD а толку. вам небось мсдн подвай или спеку. а я под рукой все это не храню
 
@vitidev Хуже того. Если у вас есть два «непересекающихся» выражения на C#, где гарантия, что в виде машинных инструкций они тоже будут непересекающимися?
@vitidev Ну да. Хабр не является источником информации
 
10:58 PM
у нас есть операции чтения и записи. еще албахари давал таблицу что может перествляться. в реале все еще строже. и барьеры и нужны для того чтобы выполнение не переставлялсоь
 
@vitidev Чтение и запись в память не имеют ничего общего с кодом на C#
Давайте покажу вам пример
 
я ничего не говорил про чтение и запись В ПАМЯТЬ
яговорил про порядок инструкций
 
@vitidev Каких инструкций?
на C#?
 
которые выполняет процессор.
 
@vitidev Угу
 
11:00 PM
он не прочтет Console.WriteLine(a) раньше чем а=1
 
Ну так порядок этих инструкций не обязан соотвествовать текстовому порядку команд на C#
@vitidev Неверно, это всего лишь as-if rule
Переменной a может вовсе не быть в памяти
 
не обязан. но барьер ему не пройти. джит вставит защиту от этого
The CLR JIT will insert a “lock or” instruction in place of the memory barrier. A locked x86 instruction has the side effect of flushing the store buffer:

mov byte ptr [ecx+4],1
lock or dword ptr [esp],0
cmp byte ptr [ecx+5],0
jne 00000013
mov byte ptr [ecx+6],1
ret
 
@vitidev И что? Вставляет, да, но куда?
 
вот про такие случаи. таких статей море. не то что про кеши
преобразуя код для выполнения его процессором вставляет такие инструкции. в итоге процессор ничего не переставит
https://msdn.microsoft.com/en-us/magazine/jj883956.aspx
начиная с x86-x64 Memory Reordering

хотя такогов инете море там подписано
Thanks to the following technical experts for reviewing this article: Joe Duffy, Eric Eilebrecht, Joe Hoag, Emad Omara, Grant Richins, Jaroslav Sevcik and Stephen Toub
джодафи и тоуб как раз те самые знатоки волатил по мнению липерта, то есть эксперты
 
Это всё круто
Но они описывают то, что происходит с конкретной версией CLR
 
11:07 PM
нет.
они описывают что ДАЖЕ в этой платформе такое может быть
 
@vitidev пруфы?
@vitidev не совсем понимаю
 
там и про х86 и про итаниум ниже и про арм
итаниум не нужен
C# Memory Model Implementation on ARM

The ARM architecture is the most recent addition to the list of architectures supported by the .NET Framework. Like Itanium, ARM has a weaker memory model than the x86-x64.

ARM Reordering Just like Itanium, ARM is allowed to freely reorder ordinary reads and writes. However, the solution that ARM provides to tame the movement of reads and writes is somewhat different from that of Itanium. ARM exposes a single instruction—DMB—that acts as a full memory barrier. No memory operation can pass over DMB in either direction.
 
Вот вам классический пример:
 
@VladD на что смотреть
 
@vitidev Давайте я скажу резко. Программист, который пишет на C# программу, которая пойдёт на интеле и не пойдёт на других платформах — негодный программист
@vitidev Смотрите на то, куда подевалась переменная count
и про то, переставил ли компилятор инструкции count++ и num &= (num-1)
 
11:11 PM
@VladD а давайте я скажу резко. вы спросиле что гарантирует в ВАШЕМ примере - я ответил "барьер". и дал пруфы того что меморибарьер превращается ДЖИТОМ в барьеры в инструкциях и что эти барьреы не позволяют через них прыгать.
а теперь можно к вашему примеру 2 переходить
 
@vitidev Нет, это не пруф.
У вас неверное предположение о том, что компилятор компилирует линейно и построчно
Это не так
 
@VladD вы хотели сказать "это не спека".
@VladD вы полагаете что барьер котоырй существует как УКАЗАТЕЛЬ разделения во что его компилить может игнорироваться джитом или другими компиляторами? может конечно, только такой компилятор никому не нужен
а куда нажать. я вижу там справа
test(int): # @test(int)
popcnt eax, edi
ret
и все
 
@vitidev да, это то, во что скомпилировался код слева
 
не верю. я попрыгал по влкладам вернулся и там уже
test(int):
popcnt eax,edi
ret
nop WORD PTR cs:[rax+rax*1+0x0]
nop
main:
xor eax,eax
ret
nop WORD PTR cs:[rax+rax*1+0x0]
nop DWORD PTR [rax]
 
суть в том, что в компиляте не обязана быть ни одна изх инструкций вашего исходника
верните -O3 -march=haswell
x86-64 clang (trunk)
поэтому когда кто-то рассуждает о том, переставит ли компилятор мои count++ и num &= (num-1), мне смешно
Компилятор вообще не обязан оставить их в коде
 
11:17 PM
@VladD конечно не обязана. даже байткод совершенной другой подход программирования.
@VladD компилятор отследит операции чтения и записи и вставит инстркуцию между ними
 
@vitidev ага, например, что случилось с чтением переменной count?
компилятору плевать на чтение и запись, он может их убрать
 
позволю заметить что это не шарп и что нет барьеров в коде. потому компилятор волен делать все что ему угодно считая что это однопоточный код
 
@vitidev То, что это не шарп, не принципиально
улучшится джиттер, и будет то же самое
 
@VladD не согласен
 
@vitidev обоснуете?
 
11:21 PM
я уже говорил. незачем джитеру стрелять себе в ногу игнорируя флаги которые для него и расставил программист
 
@vitidev Незачем, хороший аргумент
подсказка: .NET Native
Или это уже не C#?
Или вы будете писать код, который работает только на джиттере?
 
@VladD он компилит шарп. видит барьеры. зачему компилятору игнорить их если он знает зачем они там. вот компилятор под арм ничуть не игнорит, аж вообще. там если не напишешь явно вообще ничего работать не будет.
как вы говорили. джит знает что компилит фреймворк. он точно так же знает что компилит шарп )
кстати
The following implicitly generate full fences:
...
Asynchronous callbacks that use the thread pool — these include asynchronous delegates, APM callbacks, and Task continuations
...
Anything that relies on signaling, such as starting or waiting on a Task
албахари
@VladD я не пойму как ваш Engine работает с классами из другого Engine
 
@vitidev Ну барьеры он не игнорит
Но непонятно, в какую точку кода он их вставляет
Раз мы выяснили, что код может быть размазан
@vitidev Но тут у него больше свободы
И кстати наличие джита не гарантировано :)
Поэтому когда Эрик говорит, что что-то делает джит, эта информация устарела
потому что .NET Native
@vitidev А это где?
@vitidev Очень просто, вызывает их публичные методы
ну то есть никакого отличия нет
 
@VladD ну как вы любите говрить - это уже его проблемы. у барьера заявлено что через что не может прыгать - пусть джит сам парит себе мозг. Другое дело поле волатиле потому волатиле зло
@VladD а если есть код который олжен вызвать 1 публичный метод у одного обьекта а потом по ерзультатам первого у второго вызвать. это еще один Engine?
и еще не пойму как же флаги. вот у меня класс сервис. у него есть состояние - стартанул, стоит. и как снаружи читать это состояние то. просто читать
 
11:45 PM
@vitidev Ну пока непонятно, чему не разрешено через него прыгать
@vitidev Ну, обычной код: var result = await obj2.Method2(await obj1.Method1());
@vitidev А зачем флаги? Кому интересно, стартовал ли сервис?
У меня нету флага, стартовал ли сервис
есть метод service.EnsureRunning()
в одном из сервисов
но обычно всё ещё проще: если у меня есть ссылка на сервис, то он работает
 
@VladD инструкциям чтения и записи
 
@vitidev Чтения и записи в C# или машинными?
 
@VladD машинными. код с барьерами не буде так перекручиваться сильно что аж барьеры некуда будет вставить. так что разделение в машинных кодах по факту совпадет с разделение в шарпе в точках барьера.а между барьерами может быть перемешано кешировано и так далее
то есть джит и сам не будет буйствовать и процессор не будет ибо для него джит расставит инструкции.
@VladD ну это если сервис запускается при создании. а если может старт стоп сколько угодно по аналогии со службами
 

« first day (984 days earlier)      last day (2047 days later) »