Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
Почему в примере для std::atomic<bool> flag; в функции flag.compare_exchange_strong() используют memory_order_acquire, а не memory_order_acq_rel или memory_order_seq_cst ? Они ведут речь об упорядочивании команд процессором/компилятором в пределах одного потока благодаря барьеру памяти, но не об упорядочивании команд между потоками/ядрами. Допустим, что будет если два потока на двух разных ядрах одновременно выполнят инструкцию, при flag=0? if (flag.compare_exchange_strong(expected, 1, memory_order_acquire)) { ... } Тогда: - 1й поток благодаря memory_order_acquire прочитает значение flag==0 и запишет flag=1 - 2й поток благодаря memory_order_acquire снова прочитает значение flag==0 (т.к. 1й поток записал flag=1 без release), и тоже запишет flag=1 Причем это будет возникать крайне редко. Собственно вопрос, почему не memory_order_acq_rel и в каком случае понадобился бы memory_order_seq_cst? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.05.2013, 12:53 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
memory_order_acquireДопустим, что будет если два потока на двух разных ядрах одновременно выполнят инструкцию, при flag=0? if (flag.compare_exchange_strong(expected, 1, memory_order_acquire)) { ... } Тогда: - 1й поток благодаря memory_order_acquire прочитает значение flag==0 и запишет flag=1 - 2й поток благодаря memory_order_acquire снова прочитает значение flag==0 (т.к. 1й поток записал flag=1 без release), и тоже запишет flag=1 Причем это будет возникать крайне редко. Не будет этого никогда. compare_exchange_strong - это атомарная операция, которая не может быть успешной одновременно в двух потоках. А барьер относится не к самому флагу, а к командам которые предшествуют/следуют за его установкой. Если не делать барьер то возможна ситуация когда команды которые должны быть до установки флага на самом деле выполнятся уже после и наоборот, при сбросе флага. Пары барьеров acquire и release для реализации мьютекса достаточно, т.к. memory_order_seq_cst избыточно мощный (например нужен для случая когда одновременно несколько потоков выполняют действия при изменении флага, и каждый из них должен видеть действия всех потоков одинаково, как пример - очередь с несколькими потребителями: если один поток извлек сообщение, то остальные не должны его повторно извлечь). В случае же мьютекса одновременно действуют только два потока (остальные ждут), причем один из них (тот кто отпускает мьютекс) только что совершил действие, а второй (тот кто захватывает) только собирается совершить, и первому не надо читать результат второго, а второй точно знает что первый ничего нового не сделает. Это и есть семантика acquire-release. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.05.2013, 21:36 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
Anatoly Moskovskymemory_order_acquireДопустим, что будет если два потока на двух разных ядрах одновременно выполнят инструкцию, при flag=0? if (flag.compare_exchange_strong(expected, 1, memory_order_acquire)) { ... } Тогда: - 1й поток благодаря memory_order_acquire прочитает значение flag==0 и запишет flag=1 - 2й поток благодаря memory_order_acquire снова прочитает значение flag==0 (т.к. 1й поток записал flag=1 без release), и тоже запишет flag=1 Причем это будет возникать крайне редко. Не будет этого никогда. compare_exchange_strong - это атомарная операция, которая не может быть успешной одновременно в двух потоках. А барьер относится не к самому флагу, а к командам которые предшествуют/следуют за его установкой. Если не делать барьер то возможна ситуация когда команды которые должны быть до установки флага на самом деле выполнятся уже после и наоборот, при сбросе флага. Т.е. если коротко, то так? memory_order_acquire - гарантирует, что все предшествующие изменению атомарной переменной команды выполнены memory_order_release - гарантирует, что все следующие за изменением атомарной переменной команды выполнятся строго после Или наоборот? Ведь нам не так страшно, что на самом деле команды могут выполниться после после, как до установки флага, когда мьюеткс ещё не захватили, а изменения им защищаемые уже прошли. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.05.2013, 23:16 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
memory_order_acquireТ.е. если коротко, то так? memory_order_acquire - гарантирует, что все предшествующие изменению атомарной переменной команды выполнены memory_order_release - гарантирует, что все следующие за изменением атомарной переменной команды выполнятся строго после compare_exchange выглядит как запись, но на самом деле там внутри две операции: чтение флага (для проверки старого содержимого) и потом запись. Когда мы захватываем (acquire) мьютекс, то барьер относится к чтению флага и служит для предотвращения выполнения последующих команд до собственно чтения флага и проверки что мьютекс свободен. Когда мы освобождаем (release) мьютекс, то барьер относится к записи флага и служит для предотвращения выполнения предыдущих ему команд после собственно установки флага. Т.е. гарантируется такой порядок: * проверка что flag == 0 * acquire * какие-то команды которые не выйдут за пределы acquire-release * release * flag = 0 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.05.2013, 23:49 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
Да, хоть это и видно из предыдущего текста но хочу явно ответить на этот вопрос: memory_order_acquirememory_order_acquire - гарантирует, что все предшествующие изменению атомарной переменной команды выполнены memory_order_release - гарантирует, что все следующие за изменением атомарной переменной команды выполнятся строго после Или наоборот? Наоборот. acquire не пускает последующие команды до себя release не пускает предыдущие команды после себя ЗЫ.Когда речь про барьеры, под порядком команд имеются в виду не собственно порядок выполнения команд, а порядок в котором эффекты от выполнения команд видны остальным потокам. Потому что например одна команда может сохранить во внешнюю память, а другая выполненная после нее - в кеш. Для других потоков порядок будет обратный, поскольку запись в кеш будет позже увидена. Барьеры решают именно эту проблему - приводят очередность эффектов к очередности команд в коде. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 00:04 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
Anatoly MoskovskyДа, хоть это и видно из предыдущего текста но хочу явно ответить на этот вопрос: memory_order_acquirememory_order_acquire - гарантирует, что все предшествующие изменению атомарной переменной команды выполнены memory_order_release - гарантирует, что все следующие за изменением атомарной переменной команды выполнятся строго после Или наоборот? Наоборот. acquire не пускает последующие команды до себя release не пускает предыдущие команды после себя ЗЫ.Когда речь про барьеры, под порядком команд имеются в виду не собственно порядок выполнения команд, а порядок в котором эффекты от выполнения команд видны остальным потокам. Потому что например одна команда может сохранить во внешнюю память, а другая выполненная после нее - в кеш. Для других потоков порядок будет обратный, поскольку запись в кеш будет позже увидена. Барьеры решают именно эту проблему - приводят очередность эффектов к очередности команд в коде. Ясно, спасибо. Значит memory_order_acquire, memory_order_release, memory_order_acq_rel решают проблему переупорядочивания. Но тогда не совсем понимаю, чем memory_order_seq_cst сильнее, чем memory_order_acq_rel? Ведь memory_order_acq_rel уже гарантирует, что ни в одну, ни в другую сторону видимые действия команд не перескочат. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 00:16 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
memory_order_seq_cstНо тогда не совсем понимаю, чем memory_order_seq_cst сильнее, чем memory_order_acq_rel? Разница между ними следующая. memory_order_acq_rel задает порядок команд в том потоке где он применен. Т.е. другие потоки увидят эффекты команд до барьера и после барьера именно в таком порядке. Но если например таких потоков будет несколько, то остальные потоки могут видеть порядок самих барьеров разным. memory_order_seq_cst гарантирует что порядок барьеров будет одним и тем же с точки зрения каждого потока. Технически это реализуется например тем что барьер сопровождается командой блокировки внешней памяти, что гарантирует сериализацию таких команд на всех процессорах. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 00:56 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
Anatoly Moskovskymemory_order_seq_cstНо тогда не совсем понимаю, чем memory_order_seq_cst сильнее, чем memory_order_acq_rel? Разница между ними следующая. memory_order_acq_rel задает порядок команд в том потоке где он применен. Т.е. другие потоки увидят эффекты команд до барьера и после барьера именно в таком порядке. Но если например таких потоков будет несколько, то остальные потоки могут видеть порядок самих барьеров разным . memory_order_seq_cst гарантирует что порядок барьеров будет одним и тем же с точки зрения каждого потока. Технически это реализуется например тем что барьер сопровождается командой блокировки внешней памяти, что гарантирует сериализацию таких команд на всех процессорах. В смысле без memory_order_seq_cst остальные потоки могут видеть, что сначала поток 2 изменил атомарную переменную, а затем поток 1, хотя реально было наоборот, сначала 1, потом 2? А memory_order_seq_cst именно через блокировку внешней памяти реализуется или использует и какие-то команды синхронизации кэшей, или все же кэши сами решают эти проблемы используя протоколы поддержки когерентности кешей AMD MOESI / Intel MESIF , т.е. ни на каких процессорах не может быть двух одинаковых кэш-линий модифицированных по разному разными ядрами, даже если каждая из этих кэш линий в отдельном L1? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 01:15 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
memory_order_seq_cstВ смысле без memory_order_seq_cst остальные потоки могут видеть, что сначала поток 2 изменил атомарную переменную, а затем поток 1, хотя реально было наоборот, сначала 1, потом 2? Речь про две разные атомарные переменные. memory_order_seq_cstА memory_order_seq_cst именно через блокировку внешней памяти реализуется или использует и какие-то команды синхронизации кэшей Я не знаю как еще кроме блокировки шины можно это сделать. Но наверно можно и по другому (но что-то внешнее по отношению к процессору по идее заблокируется :)). memory_order_seq_cstили все же кэши сами решают эти проблемы используя протоколы поддержки когерентности кешей AMD MOESI / Intel MESIF, т.е. ни на каких процессорах не может быть двух одинаковых кэш-линий модифицированных по разному разными ядрами, даже если каждая из этих кэш линий в отдельном L1? См первый ответ. Речь не про одну переменную а разные. Поэтому когерентность не поможет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 01:31 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
Anatoly Moskovskymemory_order_seq_cstВ смысле без memory_order_seq_cst остальные потоки могут видеть, что сначала поток 2 изменил атомарную переменную, а затем поток 1, хотя реально было наоборот, сначала 1, потом 2? Речь про две разные атомарные переменные. memory_order_seq_cstА memory_order_seq_cst именно через блокировку внешней памяти реализуется или использует и какие-то команды синхронизации кэшей Я не знаю как еще кроме блокировки шины можно это сделать. Но наверно можно и по другому (но что-то внешнее по отношению к процессору по идее заблокируется :)). Ну это понятно :) Вопрос, заблокируется только ОЗУ или и кэш тоже? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 01:55 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
И отдельная ситуация, все таки на каких-то процессорах может быть две одинаковых кэш-линий модифицированных по разному разными ядрами, если допустим каждая из этих кэш линий в отдельном L1? И если может то как решается? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 02:11 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
memory_order_seq_cstВопрос, заблокируется только ОЗУ или и кэш тоже? memory_order_seq_cstИ отдельная ситуация, все таки на каких-то процессорах может быть две одинаковых кэш-линий модифицированных по разному разными ядрами, если допустим каждая из этих кэш линий в отдельном L1? И если может то как решается? Не знаю ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 02:46 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
Ок, будем считать, что memory_order_seq_cst помимо прочего, скидывает данные из L1 в L3 и RAM, а конфликты кэшей решаются исключительно на уровне протоколов когерентности кешей. И уж для полноты картины std::memory_order_consume - говорят что "prior writes to data-dependent memory locations", а в memory_order_acquire - "prior writes made to other memory locations". Непонятно только про какие other/data-dependent memory locations идет речь если мы работаем с одной и той же атомарной переменной и в чем их отличие? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 19:20 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
memory_order_seq_cstОк, будем считать, что memory_order_seq_cst помимо прочего, скидывает данные из L1 в L3 и RAM, а конфликты кэшей решаются исключительно на уровне протоколов когерентности кешей. Конечно скидывает, иначе бы он не работал, как барьер release :) memory_order_seq_cstИ уж для полноты картины std::memory_order_consume - говорят что "prior writes to data-dependent memory locations", а в memory_order_acquire - "prior writes made to other memory locations". Непонятно только про какие other/data-dependent memory locations идет речь если мы работаем с одной и той же атомарной переменной и в чем их отличие? data-dependent - например если мы записываем сообщение в структуре, а другому потоку передаем указатель на нее в атомарной переменной. memory_order_consume указанный при чтении указателя не позволяет прочесть данные по предыдущему значению указателя, а заставляют сначала прочесть новый указатель, а потом и данные по нему. Однако другие операции которые не связаны с данным указателем, могут быть переупорядочены. memory_order_acquire запрещает переупорядочивание любых последующих за ним операций. Т.е. более строгий. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.05.2013, 21:19 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
Anatoly Moskovskymemory_order_seq_cstОк, будем считать, что memory_order_seq_cst помимо прочего, скидывает данные из L1 в L3 и RAM, а конфликты кэшей решаются исключительно на уровне протоколов когерентности кешей. Конечно скидывает, иначе бы он не работал, как барьер release :) В смысле, что release не скидывает данные из L1 в L2, а только занимается пере-упорядочиванием? Anatoly Moskovskymemory_order_seq_cstВ смысле без memory_order_seq_cst остальные потоки могут видеть, что сначала поток 2 изменил атомарную переменную, а затем поток 1, хотя реально было наоборот, сначала 1, потом 2? Речь про две разные атомарные переменные. А можете привести какой-то простой кейс применения memory_order_seq_cst, а то в той же статье из хабра , если счетчик сделать атомарным, то речь как раз будет о двух атомарных переменных, но ведь memory_order_seq_cst не понадобиться же :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.06.2013, 00:00 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
memory_order_seq_cstВ смысле, что release не скидывает данные из L1 в L2, а только занимается пере-упорядочиванием? Вы зря на такой уровень опускаетесь. Когда вы применяете семантики упорядочивания то вам вообще не зачем знать про кэши. Именно для того чтобы не приходилось об этом заботиться и придумали эти абстракции. А если отвечать на вопрос - release не занимается пере-упорядочиванием, он наоборот сохраняет порядок Между release в одном потоке и acquire в другом будут произведены все необходимые "скидывания из кэшей" memory_order_seq_cstА можете привести какой-то простой кейс применения memory_order_seq_cs Мне пример лень придумывать, см. тут в конце http://en.cppreference.com/w/cpp/atomic/memory_order ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.06.2013, 00:53 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
А std::memory_order_consume в принципе можно применять не только для указателей, но и для индексов и вообще любых любых переменных/объектов зависящих от атомика с барьером std::memory_order_consume? И так, используя не указатель, а индекс, тоже можно? Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. P.S. Мда, в MSVS 2012 до сих пор не реализовали ATOMIC_VAR_INIT(), и в один из примеров в вообще валиться с ассертом. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.06.2013, 20:22 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
memory_order_consume не только дИ так, используя не указатель, а индекс, тоже можно? Индекс и указатель - это одно и то же, как лингвистически, так и с точки зрения стандарта С/С++ :) Код: plaintext 1. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.07.2013, 00:23 |
|
||
|
Почему в примере для compare_exchange_strong() используют memory_order_acquire?
|
|||
|---|---|---|---|
|
#18+
Anatoly Moskovskymemory_order_consume не только дИ так, используя не указатель, а индекс, тоже можно? Индекс и указатель - это одно и то же, как лингвистически, так и с точки зрения стандарта С/С++ :) Код: plaintext 1. Я так понял тут хоть float используй, тоже барьер сработает :) Все зависимые переменные от атомика не смогут выполниться раньше загрузки(load) из атомика. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.07.2013, 01:36 |
|
||
|
|

start [/forum/topic.php?fid=57&msg=38259381&tid=2020114]: |
0ms |
get settings: |
11ms |
get forum list: |
13ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
74ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
48ms |
get tp. blocked users: |
1ms |
| others: | 292ms |
| total: | 458ms |

| 0 / 0 |
