Информация об изменениях

Сообщение Re[7]: Прошу пояснений по синхронизации acquire-release от 08.02.2017 21:38

Изменено 08.02.2017 21:40 andrey.desman

Re[7]: Прошу пояснений по синхронизации acquire-release
Здравствуйте, DTF, Вы писали:

DTF>Но я спрашиваю немного про другой случай.

DTF>А именно, два потока ОДНОВРЕМЕННО пытаются войти в секцию (получить блокировку с memory_order_acquire). Пока что ни одной операции с memory_order_release еще нет.

Тут небольшая путаница. memory_order ты задаешь синхронизацию до/после атомарной операции.

DTF>Какой конкретно пункт в стандарте запрещает потоку A получить блокировку, но никому об этом не сказать?

DTF>Соответственно, поток B читает переменную, но видит там предыдущее состояние и тоже получает блокировку.

DTF>Почему такого никогда не будет? Или таки будет?


Потому что тогда переменная не будет атомарной, в ней будет смысла не больше, чем в volatile bool.

Попробуем так.
Операция над атомарной переменной всегда видна всем процессорам сразу. В этом ее смысл. Достигается это с помощью lock xaddl (или чем другим для флагов) или ll/sc для всяких риск-архитектур (вот, зачитай принцип https://en.wikipedia.org/wiki/Load-link/store-conditional).

В memory_order ты указываешь как будут синхронизироваться все изменения до/после атомарной операции.
Т.е. в своем коде ты можешь поставить relaxed модель и код будет работать в том смысле, что никто никакие два потока не захватят твой спинлок одновременно. Однако, все, что будет поменяно между lock() и unlock() в одном потоке не обязательно будет видно между lock() и unlock() в другом.
Для этого в твоем коде и стоит модель acquire/release.
Грубо говоря, acquire означает "давай сейчас загрузим все, что там другой поток наменял", а release означает "давай сейчас отдадим все, что мы наменяли другому потоку".
Если в терминах процессора, то acquire — это объявить все поменяные другим потоком строки кэша недействительными (invalidate), что приведет к их загрузки из памяти при следующем обращении, а release — это сбросить все поменяные строки из кэша в память. На многоядерных архитектурах с общим кэшем, очевидно, release/acquire ничего не делает. С разными кэшами будут дикие пляски.
Re[7]: Прошу пояснений по синхронизации acquire-release
Здравствуйте, DTF, Вы писали:

DTF>Но я спрашиваю немного про другой случай.

DTF>А именно, два потока ОДНОВРЕМЕННО пытаются войти в секцию (получить блокировку с memory_order_acquire). Пока что ни одной операции с memory_order_release еще нет.

Тут небольшая путаница. memory_order ты задаешь синхронизацию до/после атомарной операции, а не самой операции.

DTF>Какой конкретно пункт в стандарте запрещает потоку A получить блокировку, но никому об этом не сказать?

DTF>Соответственно, поток B читает переменную, но видит там предыдущее состояние и тоже получает блокировку.

DTF>Почему такого никогда не будет? Или таки будет?


Потому что тогда переменная не будет атомарной, в ней будет смысла не больше, чем в volatile bool.

Попробуем так.
Операция над атомарной переменной всегда видна всем процессорам сразу. В этом ее смысл. Достигается это с помощью lock xaddl (или чем другим для флагов) или ll/sc для всяких риск-архитектур (вот, зачитай принцип https://en.wikipedia.org/wiki/Load-link/store-conditional).

В memory_order ты указываешь как будут синхронизироваться все изменения до/после атомарной операции.
Т.е. в своем коде ты можешь поставить relaxed модель и код будет работать в том смысле, что никто никакие два потока не захватят твой спинлок одновременно. Однако, все, что будет поменяно между lock() и unlock() в одном потоке не обязательно будет видно между lock() и unlock() в другом.
Для этого в твоем коде и стоит модель acquire/release.
Грубо говоря, acquire означает "давай сейчас загрузим все, что там другой поток наменял", а release означает "давай сейчас отдадим все, что мы наменяли другому потоку".
Если в терминах процессора, то acquire — это объявить все поменяные другим потоком строки кэша недействительными (invalidate), что приведет к их загрузки из памяти при следующем обращении, а release — это сбросить все поменяные строки из кэша в память. На многоядерных архитектурах с общим кэшем, очевидно, release/acquire ничего не делает. С разными кэшами будут дикие пляски.