volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 31.07.15 17:46
Оценка: -3
Я тут померил:
    std::atomic<bool> a;
    std::atomic_flag af;
    volatile bool    vb = true;
    bool             b = false; 

    const auto start_time = std::chrono::high_resolution_clock::now();
    for(long i = 0; i < 1000000000; ++i)
    {
        a.store(true);
        a.load();
        //af.test_and_set();
        //af.clear();
        //vb = true;
        //b = vb;
    }
    const auto end_time = std::chrono::high_resolution_clock::now();
    const auto diff_time = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
    std::cout << "Test time:" << diff_time << " milliseconds \n";


и получилось, что volatile bool обгоняет std::atomic_flag на порядок, а std::atomic<bool> обгоняет std::atomic_flag.

    std::atomic<bool> 10031
    std::atomic_flag  13001
    volatile bool       880


Так и должно быть или я чего-то напортачил ?
И каждый день — без права на ошибку...
Re: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: Abyx Россия  
Дата: 31.07.15 18:48
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Я тут померил:


BFE>
BFE>    std::atomic<bool> 10031
BFE>    std::atomic_flag  13001
BFE>    volatile bool       880
BFE>


BFE>Так и должно быть или я чего-то напортачил ?


во-первых, volatile+многопоточность=гонки=UB
во-вторых да, так и должно быть, #lock это не дешево.
что там с atomic_flag — не знаю.
In Zen We Trust
Re: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: watchmaker  
Дата: 31.07.15 19:24
Оценка: +2
Здравствуйте, B0FEE664, Вы писали:

BFE>и получилось, что volatile bool обгоняет std::atomic_flag на порядок,

BFE>Так и должно быть или я чего-то напортачил ?

У методов store/load/test/clear ты не указываешь упорядочивание, а по умолчанию там выбирается максимально надёжный и максимально медленный std::memory_order_seq_cst.
Укажи там, например, std::memory_order_relaxed — и всё заработает куда как бодрее.
Так что если в приоритете скорость кода, то указывай явно достаточное упорядочивание. Если же в приоритете простота и скорость написания кода — то оставляй как есть.

BFE>а std::atomic<bool> обгоняет std::atomic_flag.

В общем случае атомарная запись в память быстрее чем запись и чтение (.test_and_set), так что так может быть.
Re: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: alex19  
Дата: 01.08.15 00:42
Оценка: +2
Во-первых, atomic и volatile для разных вещей.

Во-вторых, посмотри на ассемблерный код.

В-третьих, для чего все это?
Re[2]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 04.08.15 15:26
Оценка:
Здравствуйте, Abyx, Вы писали:

A>во-первых, volatile+многопоточность=гонки=UB

Тем не мене получается, что использование volatile bool может быть оптимизацией для некоторых процессоров. А именно, когда операция атомарна, процессор имеет одно ядро и гонки устраняются другими способами (или не важны).
И каждый день — без права на ошибку...
Re[3]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: Abyx Россия  
Дата: 04.08.15 18:50
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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


A>>во-первых, volatile+многопоточность=гонки=UB

BFE>Тем не мене получается, что использование volatile bool может быть оптимизацией для некоторых процессоров. А именно, когда операция атомарна, процессор имеет одно ядро и гонки устраняются другими способами (или не важны).

всё так, но если у тебя процессор с 1 ядром, ты хочешь большего быстродействия (оптимизации программы) — то это повод использовать процессор хотя бы с 8 ядрами.
In Zen We Trust
Re[3]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: ELazin http://rsdn.ru/forum/prj/6225353.1
Автор: ELazin
Дата: 26.10.15
Дата: 05.08.15 11:04
Оценка:
A>>во-первых, volatile+многопоточность=гонки=UB
BFE>Тем не мене получается, что использование volatile bool может быть оптимизацией для некоторых процессоров. А именно, когда операция атомарна, процессор имеет одно ядро и гонки устраняются другими способами (или не важны).

Твой atomic_flag скорее всего генерирует барьер, чтобы разницы между volatile bool и atomic_flag-ом не было, нужно использовать memory_order_relaxed. Какой смысл использовать все это в одном потоке — загадка.
Re[4]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 05.08.15 12:20
Оценка: -3
Здравствуйте, ELazin, Вы писали:

A>>>во-первых, volatile+многопоточность=гонки=UB

BFE>>Тем не мене получается, что использование volatile bool может быть оптимизацией для некоторых процессоров. А именно, когда операция атомарна, процессор имеет одно ядро и гонки устраняются другими способами (или не важны).

EL>Какой смысл использовать все это в одном потоке — загадка.

Так проще измерить время выполнения операции.

EL>Твой atomic_flag скорее всего генерирует барьер, чтобы разницы между volatile bool и atomic_flag-ом не было, нужно использовать memory_order_relaxed.


А какой смысл в memory_order_relaxed без барьеров памяти? Один поток может никогда не увидеть изменения сделанное в другом потоке, а это значит, что такой код будет корректно работать только если процессор имеет одно ядро, т.е. код не универсален. А какой тогда смысл использовать atomic если volatile имеет примерно такие же характеристики?
И каждый день — без права на ошибку...
Re[4]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 05.08.15 12:27
Оценка:
Здравствуйте, Abyx, Вы писали:

A>всё так, но если у тебя процессор с 1 ядром, ты хочешь большего быстродействия (оптимизации программы) — то это повод использовать процессор хотя бы с 8 ядрами.


Я не хочу большего быстродействия; меня и текущее вполне устраивает. Я хотел избавится от потенциальной проблемы volatile и сделать код универсальным, но тогда получается, что я замедлю весь код.
И каждый день — без права на ошибку...
Re[5]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: watchmaker  
Дата: 05.08.15 13:00
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>А какой смысл в memory_order_relaxed без барьеров памяти? Один поток может никогда не увидеть изменения сделанное в другом потоке,


Какое-то страшно неверное понимание работы флага memory_order_relaxed. Его указание говорит об упорядоченности относительно других операций с памятью, а не об видимости изменений. С видимостью никаких проблем нет.

Если один поток должен передать данные другому, то достаточно использовать memory_order_relaxed, если все данные содержатся в самом atomic (например, atomic<int> содержит в себе возвращаемое значение функции), или memory_order_release, если данные содержатся в каком-то другом хранилище (например, когда поток записывает ответ в глобальный vector<int>, а потом устанавливает флаг atomic<bool> как признак готовности результата).


BFE> А какой тогда смысл использовать atomic если volatile имеет примерно такие же характеристики?


Они служат для разных целей!
Ну и если уж говорить про memory_order_relaxed, то как ты думаешь, какими гарантиями на упорядоченность обладают операции с volatile переменными? Там ситуация даже хуже чем с atomic+memory_order_relaxed. Если не используются расширения компилятора (вроде упомянутого по ссылке Abyx /volatie:ms), то volatile доступ лишь не перемешивается с доступом к другим volatile-переменным, но при этом не вводит никаких барьеров и свободно перемешивается с другими записями/чтениями из памяти. Вот из-за этого и нужно для синхронизации потоков использовать atimic, а не volatile — c atomic можно написать корректный переносимый алгоритм, а с volatile, кроме совсем тривиальных случаев, — нет.
Re[5]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: ELazin http://rsdn.ru/forum/prj/6225353.1
Автор: ELazin
Дата: 26.10.15
Дата: 05.08.15 13:46
Оценка:
BFE>А какой смысл в memory_order_relaxed без барьеров памяти? Один поток может никогда не увидеть изменения сделанное в другом потоке, а это значит, что такой код будет корректно работать только если процессор имеет одно ядро, т.е. код не универсален.

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

Мало того, так как на x86 сохранения не переупорядочиваются с другими сохранениями а загрузки не переупорядочиваются с другими загрузками, то компилятор не будет в релизе вставлять барьеры и префиксы lock вообще, если ты используешь что-то слабее memory_order_seq_cst.

BFE>А какой тогда смысл использовать atomic если volatile имеет примерно такие же характеристики?


Это аннотация для читателя кода. Может memory_order_acquire(release) не будут генерировать барьеры на той архитектуре, под которую я пишу, тем не менее, когда я увижу использование этих флагов я сразу пойму, что имеется ввиду read acquire/write release, т.е. перед сохранением с release где-то записывается значение а после загрузки с acquire оно может считываться. Т.е. требуется определенный порядок без переупорядочивания загрузок/сохранений, код зависит от этого порядка и он обозначен явно. А если я вижу volatile я понимаю ничего, может это нужно чтобы обойти какую-нибудь багу, вызванную слишком агрессивными оптимизациями в компиляторе?
Re[6]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 05.08.15 14:41
Оценка:
Здравствуйте, watchmaker, Вы писали:

BFE>>А какой смысл в memory_order_relaxed без барьеров памяти? Один поток может никогда не увидеть изменения сделанное в другом потоке,


W>Какое-то страшно неверное понимание работы флага memory_order_relaxed. Его указание говорит об упорядоченности относительно других операций с памятью, а не об видимости изменений. С видимостью никаких проблем нет.

Откуда следует, что нет никаких проблем с видимостью? Подозреваю, что из практики, а не из стандарта.

W>Если один поток должен передать данные другому, то достаточно использовать memory_order_relaxed,

Откуда это следует?

BFE>> А какой тогда смысл использовать atomic если volatile имеет примерно такие же характеристики?

W>Они служат для разных целей!
Созданы они для других целей, но это не значит, что их нельзя использовать.

W>Ну и если уж говорить про memory_order_relaxed, то как ты думаешь, какими гарантиями на упорядоченность обладают операции с volatile переменными?

Никакими. Но что, если мне никакие гарантии упорядоченности не нужны?
И каждый день — без права на ошибку...
Re[7]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: watchmaker  
Дата: 05.08.15 15:07
Оценка: :)
Здравствуйте, B0FEE664, Вы писали:

W>>Какое-то страшно неверное понимание работы флага memory_order_relaxed. Его указание говорит об упорядоченности относительно других операций с памятью, а не об видимости изменений. С видимостью никаких проблем нет.

BFE>Откуда следует, что нет никаких проблем с видимостью? Подозреваю, что из практики, а не из стандарта.
Подозреваешь? И слышал о стандарте? Тогда что же тебя удерживает от того, чтобы открыть его и избавится от подозрений?

§1.10/28

W>>Если один поток должен передать данные другому, то достаточно использовать memory_order_relaxed,

BFE>Откуда это следует?
Не надо вырывать из предложения часть.

BFE>>> А какой тогда смысл использовать atomic если volatile имеет примерно такие же характеристики?

W>>Они служат для разных целей!
BFE>Созданы они для других целей, но это не значит, что их нельзя использовать.
Безусловно. Только область использования по сравнению с atomic оказывается крайне ограниченной — множество вещей, возможные с atomic, просто не реализуются через volatile.
Попробуй, например, реализовать уже упомянутый сценарий: поток А заполняет глобальный вектор данными и сигнализирует ждущему потоку Б о готовности результата; после чего поток Б, например, выводит в stdout его содержимое. С atomic такая логика реализуется элементарно. Теперь сделай это с volatile.

BFE>Никакими. Но что, если мне никакие гарантии упорядоченности не нужны?

Тогда memory_order_relaxed — твой выбор.
Re[6]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 05.08.15 15:11
Оценка:
Здравствуйте, ELazin, Вы писали:

BFE>>А какой смысл в memory_order_relaxed без барьеров памяти? Один поток может никогда не увидеть изменения сделанное в другом потоке, а это значит, что такой код будет корректно работать только если процессор имеет одно ядро, т.е. код не универсален.

EL>Очень странные представления о том, как происходит запись в память. Почему изменения не будут видимы? Relaxed означает что процессор может переупорядочить запись в эту переменную с записью в другие переменные, другие флаги запрещают определенные переупорядочивания.

Для atomic объектов гарантируются три различные характеристики: атомарность, видимость и упорядоченность. Так вот, конкретно для relaxed операций нет никаких гарантий упорядоченности, а это значит, что их видимость обеспечивается только расплывчатой фразой про конечный период времени:

An implementation should ensure that the last value (in modification order) assigned by an atomic or
synchronization operation will become visible to all other threads in a finite period of time.

Более того, в примечании 1.10/5 прямо сказано, что операции над relaxed объектами не являются синхронизирующими операциями. А это, по моему мнению, означает ровно одно: две нитки могут видеть разные значения одной и той же переменной, т.к. иначе на таких объектах можно было бы построить синхронизацию.

EL>Мало того, так как на x86 сохранения не переупорядочиваются с другими сохранениями а загрузки не переупорядочиваются с другими загрузками, то компилятор не будет в релизе вставлять барьеры и префиксы lock вообще, если ты используешь что-то слабее memory_order_seq_cst.


У меня таргет платформа ARM, а не x86. (Замеры на ней дают схожие результаты по времени).

BFE>>А какой тогда смысл использовать atomic если volatile имеет примерно такие же характеристики?

EL>Это аннотация для читателя кода.
Ну, есть ещё и комментарии.
И каждый день — без права на ошибку...
Re[8]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 05.08.15 15:16
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>>>Какое-то страшно неверное понимание работы флага memory_order_relaxed. Его указание говорит об упорядоченности относительно других операций с памятью, а не об видимости изменений. С видимостью никаких проблем нет.

BFE>>Откуда следует, что нет никаких проблем с видимостью? Подозреваю, что из практики, а не из стандарта.
W>Подозреваешь?
Да.
W>И слышал о стандарте?
И даже читал местами.

W> Тогда что же тебя удерживает от того, чтобы открыть его и избавится от подозрений?

W>§1.10/28
Вот это загадочная фраза: "finite period of time". Сколько это? 2 секунды? 2 минуты? Год?

BFE>>Никакими. Но что, если мне никакие гарантии упорядоченности не нужны?

W>Тогда memory_order_relaxed — твой выбор.

Это всё равно, что считать, что sizeof(int) равно 4. Сдаётся мне, что memory_order_relaxed ждёт та же плачевная участь...
И каждый день — без права на ошибку...
Re[9]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: uzhas Ниоткуда  
Дата: 05.08.15 15:40
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Вот это загадочная фраза: "finite period of time". Сколько это? 2 секунды? 2 минуты? Год?


фраза загадочная, но стандарт никогда и не пытался зафиксировать какие-то ограничения по времени. максимум — это зафиксировать сложность STL алгоритмов в big-O нотации, причем в сложности учитываются лишь кол-во сравнений (а не вообще все операции)
сколько по стандарту может выполняться код
int i = 0;
++i;

минуту? год? почему бы и нет
смысл фразы "finite period of time" в том, что абстрактная машина должна все же что-то сделать магическое, чтобы новое значение переменной когда-то было увидено в другом потоке. ей запрещено ничего не делать по этому поводу

по поводу visibility и ordering тебе уже отвечали в соседних ветках несколько месяцев назад и ты даже Вильямса читал, но у тебя в голове барьер (гы-гы) какой-то. ты никак не можешь понять, что вещи хоть и взаимосвязанные, но разные. в языке нет средств для ускорения visibility, но есть средства получения предсказуемости при изменении нескольких ячеек памяти.
на пальцах:
если ты меняешь две переменные и как-то используешь ордеринг, то как только другой поток увидел новое значение у первой переменной, то он уже может полагаться на значение у второй переменной согласно описанным законам в стандарте. но при этом ты не знаешь когда же второй поток увидит новое значение у первой переменной (нет возможности влиять на visibility)
исключениями я бы назвал RMW операции (даже с relaxed order), где есть гарантия получить свежее значение (хотя опять не ясно через сколько лет)

первые же ссылки из гугла дают полезную инфу на эту тему:
http://stackoverflow.com/questions/7461484/memory-model-ordering-and-visibility
http://stackoverflow.com/questions/13009411/thread-synchronization-how-to-guarantee-visibility-of-writes?lq=1

no hardware memory model makes any guarantees about eventual visibility for writes

Re[10]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 05.08.15 17:39
Оценка:
Здравствуйте, uzhas, Вы писали:

BFE>>Вот это загадочная фраза: "finite period of time". Сколько это? 2 секунды? 2 минуты? Год?

U>фраза загадочная, но стандарт никогда и не пытался зафиксировать какие-то ограничения по времени. максимум — это зафиксировать сложность STL алгоритмов в big-O нотации, причем в сложности учитываются лишь кол-во сравнений (а не вообще все операции)
U>сколько по стандарту может выполняться код
U>
U>int i = 0;
U>++i;
U>

U>минуту? год? почему бы и нет
U>смысл фразы "finite period of time" в том, что абстрактная машина должна все же что-то сделать магическое, чтобы новое значение переменной когда-то было увидено в другом потоке. ей запрещено ничего не делать по этому поводу
Я согласен, что оперировать абсолютными значениями времени было бы глупо, однако никаких гарантий видимости эта фраза не даёт. Это не значит, что relaxed операции не нужны. relaxed операции нужны тогда, когда операции синхронизации программист берёт на себя и делает их с помощью других средств языка, например, с помощью барьеров.

U>по поводу visibility и ordering тебе уже отвечали в соседних ветках несколько месяцев назад и ты даже Вильямса читал, но у тебя в голове барьер (гы-гы) какой-то. ты никак не можешь понять, что вещи хоть и взаимосвязанные, но разные. в языке нет средств для ускорения visibility, но есть средства получения предсказуемости при изменении нескольких ячеек памяти.

Я понимаю, что visibility и ordering это разные, хотя и связанные понятия. Что такое "ускорение visibility" я не знаю, но только вот visibility к получению предсказуемости при изменении нескольких ячеек памяти имеет весьма опосредованное отношение.

U>на пальцах:

U>если ты меняешь две переменные и как-то используешь ордеринг, то как только другой поток увидел новое значение у первой переменной, то он уже может полагаться на значение у второй переменной согласно описанным законам в стандарте. но при этом ты не знаешь когда же второй поток увидит новое значение у первой переменной (нет возможности влиять на visibility)

Есть явная гарантия получения "актуального" значения при использовании операций ведущих к синхронизации:
1.10/8

Certain library calls synchronize with other library calls performed by another thread. For example, an
atomic store-release synchronizes with a load-acquire that takes its value from the store.



U>исключениями я бы назвал RMW операции (даже с relaxed order), где есть гарантия получить свежее значение (хотя опять не ясно через сколько лет)

Нет такой гарантии.
Если в одном потоке есть вызов:

flag.clear(std::memory_order_relaxed);

а в другом:
    do
    {
    }while(flag.test_and_set(std::memory_order_relaxed));


то гарантии, что второй поток когда-либо выйдет из цикла нет.

На практике такого не случается, однако это не значит, что такого не может быть согласно стандарту. Представьте себе платформу, где два процессора и где кэши этих процессоров согласуются специальными инструкциями, которые отсутствуют при relaxed операциях.

U>первые же ссылки из гугла дают полезную инфу на эту тему:

U>http://stackoverflow.com/questions/7461484/memory-model-ordering-and-visibility
U>http://stackoverflow.com/questions/13009411/thread-synchronization-how-to-guarantee-visibility-of-writes?lq=1
U>

U>no hardware memory model makes any guarantees about eventual visibility for writes


Завтра почитаю более внимательно, но пока что я не вижу противоречий с моей точкой зрения.
И каждый день — без права на ошибку...
Re[11]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: watchmaker  
Дата: 05.08.15 18:20
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>то гарантии, что второй поток когда-либо выйдет из цикла нет.


BFE>На практике такого не случается, однако это не значит, что такого не может быть согласно стандарту. Представьте себе платформу, где два процессора и где кэши этих процессоров согласуются специальными инструкциями, которые отсутствуют при relaxed операциях.


Не надо путать абстрактную машину C++ и реальное аппаратное обеспечение. Если рассмотреть такой компьютер, где для синхронизации нужны особые инструкции, то компилятор бы их всегда и использовал. Даже если в коде требуется лишь memory_order_relaxed. Использовал бы компилятор эти инструкции в частности из-за того, что в противном случае был бы нарушен тот самый пункт о конечности времени на распространение изменений.
Так что memory_order_relaxed ни к каким вечным циклам не приведёт. Просто на таком компьютере операции с memory_order_relaxed будут выполнятся примерно так же, как и с более строгими требованиями — через эти самые специальные инструкции по синхронизации кешей.
Re[11]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: uzhas Ниоткуда  
Дата: 06.08.15 09:37
Оценка: 1 (1)
Здравствуйте, B0FEE664, Вы писали:

BFE>Есть явная гарантия получения "актуального" значения при использовании операций ведущих к синхронизации:

BFE>1.10/8
BFE>

BFE>Certain library calls synchronize with other library calls performed by another thread. For example, an
BFE>atomic store-release synchronizes with a load-acquire that takes its value from the store.


я не уверен, что твоя интерпретация этой цитаты корректна. надо мне вспомнить что такое "synchronize with"

U>>исключениями я бы назвал RMW операции (даже с relaxed order), где есть гарантия получить свежее значение (хотя опять не ясно через сколько лет)

BFE>Нет такой гарантии.

так вот же стандарт:

29.3 Order and Consistency [atomics.order]
...
11 Atomic read-modify-write operations shall always read the last value (in the modification order) written
before the write associated with the read-modify-write operation.

Re[12]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: uzhas Ниоткуда  
Дата: 06.08.15 10:04
Оценка:
Здравствуйте, uzhas, Вы писали:

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


BFE>>Есть явная гарантия получения "актуального" значения при использовании операций ведущих к синхронизации:

BFE>>1.10/8
BFE>>

BFE>>Certain library calls synchronize with other library calls performed by another thread. For example, an
BFE>>atomic store-release synchronizes with a load-acquire that takes its value from the store.


U>я не уверен, что твоя интерпретация этой цитаты корректна. надо мне вспомнить что такое "synchronize with"


Вильямс походу не в курсе о получении актуального значения через release/acquire : http://stackoverflow.com/questions/8819095/concurrency-atomic-and-volatile-in-c11-memory-model

In the absence of any additional synchronization, if one thread writes a value to ai then there is nothing that guarantees that another thread will see the value in any given time period. The standard specifies that it should be visible "in a reasonable period of time", but any given access may return a stale value.

Re[12]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 01.09.15 17:00
Оценка:
Здравствуйте, uzhas, Вы писали:

U>так вот же стандарт:

U>

U>29.3 Order and Consistency [atomics.order]
U>...
U>11 Atomic read-modify-write operations shall always read the last value (in the modification order) written
U>before the write associated with the read-modify-write operation.


Это они хорошо спрятали — аж в другом разделе. Но мой взгляд это прямо противоречит тому, что

29.3/(1.1) — memory_order_relaxed: no operation orders memory.

И каждый день — без права на ошибку...
Re[13]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 01.09.15 17:02
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Вильямс походу не в курсе о получении актуального значения через release/acquire : http://stackoverflow.com/questions/8819095/concurrency-atomic-and-volatile-in-c11-memory-model

U>

U>In the absence of any additional synchronization, if one thread writes a value to ai then there is nothing that guarantees that another thread will see the value in any given time period. The standard specifies that it should be visible "in a reasonable period of time", but any given access may return a stale value.


Ниже он пишет:

The only way to guarantee you have the "latest" value is to use a read-modify-write operation such as exchange(), compare_exchange_strong() or fetch_add(). Read-modify-write operations have an additional constraint that they always operate on the "latest" value, so a sequence of ai.fetch_add(1) operations by a series of threads will return a sequence of values with no duplicates or gaps. In the absence of additional constraints, there's still no guarantee which threads will see which values though.

И каждый день — без права на ошибку...
Re[13]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: uzhas Ниоткуда  
Дата: 03.09.15 07:10
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Но мой взгляд это прямо противоречит тому, что


BFE>

BFE>29.3/(1.1) — memory_order_relaxed: no operation orders memory.


я не вижу противоречия, т.к. первая цитата о видимости, а вторая о переупорядочивании, а это разные вещи
Re[14]: volatile bool vs std::atomic_flag vs std::atomic<boo
От: uzhas Ниоткуда  
Дата: 03.09.15 07:12
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Ниже он пишет:

BFE>

BFE>The only way to guarantee you have the "latest" value is to use a read-modify-write operation such as exchange(), compare_exchange_strong() or fetch_add(). Read-modify-write operations have an additional constraint that they always operate on the "latest" value, so a sequence of ai.fetch_add(1) operations by a series of threads will return a sequence of values with no duplicates or gaps. In the absence of additional constraints, there's still no guarantee which threads will see which values though.


все правильно он пишет, тебя что-то здесь смущает?
Отредактировано 03.09.2015 9:12 uzhas . Предыдущая версия .
Re[15]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 03.09.15 08:44
Оценка:
Здравствуйте, uzhas, Вы писали:

U>все правильно он пишет, тебе что-то здесь смущает?


Я до конца так и не разобрался, так что меня многое смущает. Например, ваша фраза:

Вильямс походу не в курсе о получении актуального значения через release/acquire

Что понимается под словосочетанием "актуальное значение"?
И каждый день — без права на ошибку...
Re[16]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: uzhas Ниоткуда  
Дата: 03.09.15 09:31
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Что понимается под словосочетанием "актуальное значение"?


the last value (in the modification order)

Re[17]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 03.09.15 09:53
Оценка:
Здравствуйте, uzhas, Вы писали:

BFE>>Что понимается под словосочетанием "актуальное значение"?


U>

U>the last value (in the modification order)


Но ведь это last value не имеет никакого отношения ко времени, а имеет отношение только к некоторой последовательности. Т.е. полученное значение вовсе не обязано быть последним по времени. Так?
И каждый день — без права на ошибку...
Re[12]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: B0FEE664  
Дата: 03.09.15 11:16
Оценка:
Здравствуйте, watchmaker, Вы писали:

BFE>>то гарантии, что второй поток когда-либо выйдет из цикла нет.

BFE>>На практике такого не случается, однако это не значит, что такого не может быть согласно стандарту. Представьте себе платформу, где два процессора и где кэши этих процессоров согласуются специальными инструкциями, которые отсутствуют при relaxed операциях.

W>Не надо путать абстрактную машину C++ и реальное аппаратное обеспечение. Если рассмотреть такой компьютер, где для синхронизации нужны особые инструкции, то компилятор бы их всегда и использовал. Даже если в коде требуется лишь memory_order_relaxed. Использовал бы компилятор эти инструкции в частности из-за того, что в противном случае был бы нарушен тот самый пункт о конечности времени на распространение изменений.

W>Так что memory_order_relaxed ни к каким вечным циклам не приведёт. Просто на таком компьютере операции с memory_order_relaxed будут выполнятся примерно так же, как и с более строгими требованиями — через эти самые специальные инструкции по синхронизации кешей.

Вот откуда следует, что писатели компилятора должны вставлять инструкции синхронизации для relaxed операций, если стандарт прямо говорит, что relaxed операции не являются операциями синхронизации?
Более того, для relaxed операций вообще не определён никакой порядок изменений (modification order), кроме sequenced before, который относится только с одной нитке.
И каждый день — без права на ошибку...
Re[13]: volatile bool vs std::atomic_flag vs std::atomic<bool>
От: watchmaker  
Дата: 04.09.15 19:22
Оценка:
Здравствуйте, B0FEE664, Вы писали:

W>>Так что memory_order_relaxed ни к каким вечным циклам не приведёт. Просто на таком компьютере операции с memory_order_relaxed будут выполнятся примерно так же, как и с более строгими требованиями — через эти самые специальные инструкции по синхронизации кешей.


BFE>Вот откуда следует, что писатели компилятора должны вставлять инструкции синхронизации для relaxed операций,

Из твоего описания процессора и из уже упомянутого §1.10/28. Если процессор требует ручного указания на распространения изменений из кеша, то компилятору придётся вставлять "инструкции по синхронизации кешей" после relaxed операций чтобы гарантировать что сделанные изменения когда-нибудь будут увидены другие процессорами.
При этом, например, оптимизирующему компилятору разрешено вставлять лишь одну "инструкцию по синхронизации кешей" для блока идущих подряд relaxed операций над разными переменными, так что не придётся вызывать потенциально дорогую "инструкцию по синхронизации кешей" каждый раз. Так что не каждая атомарная операция обязана завершаться командой на распространение изменений из кеша. Но, разумеется, компилятор должен гарантировать, что между записью и началом распространения видимости пройдёт лишь «finite period of time», и поэтому он не сможет унести эту инструкцию слишком далеко.

Если ты знаком с x86, то там есть очень похожая ситуация с инструкциями non-temporal store. Их, конечно, никто не использует для атомарных операций (и без них на x86 с этим всё хорошо), но в остальном их поведение как раз очень похоже на поведение описанного тобой гипотетического компьютера. Если поток выполняет несколько операций non-temporal store, то процессор не только не гарантирует, что эти изменения увидятся другими процессорами в каком-то там порядке, но вообще не гарантирует, что эти изменения будут видимы другими процессорами. Разумеется до тех пор, пока записывающий процессор явно не исполнит инструкцию, которая сделает эти изменения видимыми другим (хотя, опять же не гарантируется порядок, в котором другие процессоры могут наблюдать эти изменения).
И если компилятор самостоятельно решает использовать non-temporal store, то после блока таких записей он вставляет инструкцию по синхронизации памяти (проверь с icc).
Так что не нужно переживать тут за relaxed atomic — если барьеры компилятором не вставляются, то значит с этой моделью памяти они и не нужны, а совсем не значит, что у компилятора с ними какие-то сложности. А там где требуется ручная синхронизация кеша и памяти, как видно на примере icc и non-temporal store, компилятор сам делает всё что нужно. И если будут переносить компилятор на такую гипотетическую машину, то просто заиспользуют повторно эту логику, но уже для более общего набора операций.

BFE>если стандарт прямо говорит, что relaxed операции не являются операциями синхронизации?

А это тут ни при чём.
Синхронизация, атомарность, видимость — это всё разные вещи, зачем их смешивать в одну кучу?


BFE>Более того, для relaxed операций вообще не определён никакой порядок изменений (modification order), кроме sequenced before, который относится только с одной нитке.

Верно. И на практике так бывает. В чём проблема-то? Именно это и позволяет на многих архитектурах реализовать атомарные операции эффективно. Во многих задачах (например, просигнализировать через одиночный булев флаг одному потоку из другого о том, что нужно начинать или заканчивать работу) эти ограничения на порядок видимости никак не влияют на корректность алгоритма. И поэтому быстроработающие relaxed операции использовать предпочтительнее в реализации таких алгоритмов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.