Search
Write a publication
Pull to refresh

Comments 9

Какой ад, хорошо что на практике об это не нужно думать

Думать может и не надо, но пользоваться инструментом всегда проще понимая как он работает.

И, да, это еще не весь ад, весь ад если подтянуть реализацию в много ядерном процессоре и его кешах. Вот там адище еще тот....

В зависимости от практики, конечно, но в широком смысле в материале описан подход к линеаризации процесса. Актуален даже при построении workflow мышкой. В go есть реализация в виде sync.RWMutex, можно поделать весёлые `livelock`и, чтобы проникнуться статьей.

На практике оно может и не надо, но у скуфа-сеньора теперь есть +1 способ завалить вас на собесе. Хотя у него их и так полно

Кажется, явтор не понимает, что есть три явления, и они все разные:

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

  2. Даже в пределах одного потока исполнения (одной нити), компилятор может изменить последовательность действий, если это ему так удобно и если это не меняет семантики кода. При этом для данной конкретной нити ничего не изменится, но если нить имеет доступ к памяти, к которой имеет доступ другие нити, то "глядя со стороны", порядок действий с памятью может измениться.

  3. При исполнении последовательного кода процессор может переупорядочивать инструкции или операции обращения к памяти таким образом, что с точки зрения самого этого последовательного кода ничего не меняется, но глядя с другого ядра (а не нити, как в предыдущем случае) можно увидеть другой порядок обращения к памяти

Чтобы со всем этим можно было жить, существуют примитивы синхронизации, и они разные для разных случаев.

Барьеры памяти - это примитивы синхронизации между ядрами процессора (но разумеется, и компилятор не переставляет последовательные действия мимо барьера).

По поводу трех описанных явлений, мне сложно что-то ответить, поскольку они и описаны в статье.

Чтобы со всем этим можно было жить, существуют примитивы синхронизации, и они разные для разных случаев.

Вот я и постарался понять а такие ли примитивы синхронизации разные. Об этом и статья. Если Вы укажите по вашему списку какие примитивы синхронизации для какого явления стоит использовать я был бы благодарен. Обязательно посмотрю их реализацию и дополню статью.

Барьеры памяти - это примитивы синхронизации между ядрами процессора (но разумеется, и компилятор не переставляет последовательные действия мимо барьера).

Во время изучения темы я узнал про StoreBuffer. Когда поток изменяет данные, они не кладутся в кеш на прямую. А кладутся в некий буфер. Этот буфер не является общим, т.е. он принадлежит только этому потоку. Чтобы два потока могли синхронизироваться, эти данные нужно сбросить в общий ресурс. Тут на помощь приходят барьеры памяти. Которые и выполняют эту роль, именно поэтому они и наблюдаются в ассемблерных инструкциях примитивов синхронизации. Но возможно мои источники недостоверны, буду рад если поправите.

Было очень интересно узнать о том, как все это устроено в Go. Спасибо за понятную статью!

Sign up to leave a comment.

Articles