Как атомарно прочитать значение в x86 ASM?

Я знаю, как атомарно записать значение в x86 ASM. Но как мне его прочитать? Префикс LOCK нельзя использовать с mov.

Чтобы увеличить значение, я делаю:

lock inc dword ptr Counter

Как читать Counter потокобезопасным способом?


person IamIC    schedule 28.07.2010    source источник


Ответы (4)


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

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

person Mike Caron    schedule 28.07.2010
comment
Не всегда! Если адрес памяти находится в кеше, который использует второй ЦП в многопроцессорном блоке, чтение не гарантируется атомарным. Так что используйте LOCK CMPXCHG EAX, [var] который сначала ограждает кеш памяти. - person GJ.; 28.07.2010
comment
@GJ: Я думаю, что это относится только к смещенным данным - обычно у вас не было бы смещенных данных, так что это не должно быть проблемой? - person Paul R; 28.07.2010
comment
Я знаю, что чтение не будет атомарным, но это все равно будет снимок, а это значит, что значение должно быть правильным, верно? Даже если у вас было 2 ЦП и их кеш синхронизировался, я не думаю, что LOCK будет играть какую-либо роль в обеспечении того, чтобы значение было последним до того, как var будет прочитана ... или будет? - person IamIC; 28.07.2010
comment
@Paul R: Не в том случае, если два потока работают одновременно, каждый из которых работает на своем процессоре, и обращаются к какому-то адресу памяти. В этом случае необходима синхронизация кеша. Некоторые инструкции, такие как LOCK CMPXCHG, делают это автоматически. Такие инструкции, как MOV, нуждаются в первой инструкции ограничения памяти для синхронизации кэшированной памяти. См.: Руководства разработчика программного обеспечения для архитектур Intel® 64 и IA-32. Я добавил ссылки в свой ответ. - person GJ.; 28.07.2010
comment
@GJ.: mov загрузка/сохранение является атомарным, если адрес выровнен. x86 имеет согласованные кеши, поэтому даже если несколько процессоров читают/записывают одно и то же место, вы не получите разрыва, если значение не выровнено. - person Peter Cordes; 01.01.2018

Как я объясню вам в этот< /а> сообщение:

Процессы Intel Core 2 Duo, Intel Core Duo, Pentium M, Pentium 4, Intel Xeon, семейство P6, Pentium и Intel486 не гарантируют, что доступ к кэшируемой памяти, разделенной по ширине шины, строкам кэша и границам страниц, будет атомарным. процессоры. Процессоры семейства Intel Core 2 Duo, Intel Core Duo, Pentium M, Pentium 4, Intel Xeon и P6 обеспечивают сигналы управления шиной, которые позволяют подсистемам внешней памяти делать разделенный доступ атомарным; однако доступ к невыровненным данным серьезно повлияет на производительность процессора, и его следует избегать.

Так что используйте:

LOCK        CMPXCHG   EAX, [J]

LOCK CMPXCHG сначала выделяет кэш-память, а затем сравнивает EAX с целевым значением, если целевое значение не равно, то результатом в EAX является целевое значение.

РЕДАКТИРОВАТЬ: ССЫЛКИ на:

Руководства для разработчиков программного обеспечения для архитектур Intel® 64 и IA-32

В Том 3A: Руководство по системному программированию см. раздел 8.1.1.

Также проверьте: раздел Справочного руководства по оптимизации: ГЛАВА 7 ОПТИМИЗАЦИЯ ИСПОЛЬЗОВАНИЯ КЭША

person GJ.    schedule 28.07.2010
comment
Это не скомпилируется, так как [J] является указателем памяти. Это должно быть значение регистра. Это уловка-22, которую я не могу обойти. - person IamIC; 28.07.2010
comment
Из вашего другого поста я вижу, что это на самом деле не проблема, если значение выровнено и соответствует ширине шины ЦП. - person IamIC; 28.07.2010
comment
@IamIC: Точно не ширина шины. Наименьшим общим знаменателем гарантий Intel и AMD является то, что mov load/store является атомарным , если он не пересекает 8-байтовую границу (для кэшированный доступ). Или для некэшированного, если он выровнен, или 16-битный доступ, который не пересекает границу двойного слова. Также [J] — это просто абсолютный или (в x86-64) относительный режим адресации RIP. Это не двойное обращение. Собирается просто отлично. Синтаксис MASM часто опускает [], но они необязательны в MASM и обязательны в NASM. - person Peter Cordes; 01.01.2018
comment
В любом случае, проголосовали за то, что неправильно подразумевали, что вам нужно lock cmpxchg для загрузки. Для статических данных просто используйте ALIGN 4 перед меткой J:. - person Peter Cordes; 01.01.2018
comment
Где я такое подразумеваю? - person IamIC; 01.01.2018

Для простого чтения, это в основном о выравнивании. Самый простой способ обеспечить атомарное чтение — всегда использовать «естественное» выравнивание, т. е. выравнивание не меньше размера элемента (например, 32-битный элемент выравнивается по 32-битному).

Смещенные чтения не обязательно являются атомарными. В качестве крайнего примера рассмотрим чтение 32-битного значения по нечетному адресу, где первый байт находится в одной строке кэша, а остальные три байта — в другой строке кэша. В таком случае атомарное чтение практически невозможно.

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

person Jerry Coffin    schedule 28.07.2010

Интересно почитать другие ответы. Я думаю, что @GJ, вероятно, при деньгах.

В течение многих лет всегда было верно, что 32-битное чтение и запись были атомарными. Только в последние годы с действительно агрессивным кэшированием это больше не гарантируется.

Думаю, именно поэтому я предпочитаю C++, Java или что-то в этом роде между собой и машинным кодом. В наши дни машинный код слишком сложен, чтобы его можно было надежно написать (если только вы не делаете это много, чтобы не оттачивать свои навыки). К счастью, современные оптимизирующие компиляторы настолько хороши, что вам редко нужна производительность оптимизированного вручную ассемблера.

person Michael J    schedule 28.07.2010
comment
C++ не гарантирует ничего в отношении семантики памяти выше того, что делает ЦП, равно как и Java без volatile. - person Axel Gneiting; 27.08.2012
comment
C++ может гарантировать атомарный доступ для атомарных типов (вещи C++11), как и C (C11). - person Marwan Burelle; 03.06.2014