Может ли x86 переупорядочить узкий магазин с более широкой загрузкой, которая полностью его содержит?
Руководство разработчика программного обеспечения для архитектуры Intel® 64 и IA-32 говорит:
8.2.3.4 Грузы могут быть переупорядочены с более ранними магазинами в разные места
Модель упорядочения памяти Intel-64 позволяет переупорядочивать нагрузку с более ранним хранилищем в другое место. Однако грузы не переупорядочиваются с магазинами в одном и том же месте.
Как насчет нагрузок, которые частично или полностью перекрывают предыдущие магазины, но не имеют одинаковый начальный адрес? (См. Конец этой статьи для конкретного случая)
Предположим, следующий C-подобный код:
// lock - pointer to an aligned int64 variable
// threadNum - integer in the range 0..7
// volatiles here just to show direct r/w of the memory as it was suggested in the comments
int TryLock(volatile INT64* lock, INT64 threadNum)
{
if (0 != *lock)
return 0; // another thread already had the lock
((volatile INT8*)lock)[threadNum] = 1; // take the lock by setting our byte
if (1LL << 8*threadNum != *lock)
{ // another thread set its byte between our 1st and 2nd check. unset ours
((volatile INT8*)lock)[threadNum] = 0;
return 0;
}
return 1;
}
Или его эквивалент x64 asm:
; rcx - address of an aligned int64 variable
; rdx - integer in the range 0..7
TryLock PROC
cmp qword ptr [rcx], 0
jne @fail
mov r8, rdx
mov rax, 8
mul rdx
mov byte ptr [rcx+r8], 1
bts rdx, rax
cmp qword ptr [rcx], rdx
jz @success
mov byte ptr [rcx+r8], 0
@fail:
mov rax, 0
ret
@success:
mov rax, 1
ret
Затем предположим, что TryLock одновременно выполняется в двух потоках:
INT64 lock = 0;
void Thread_1() { TryLock(&lock, 1); }
void Thread_5() { TryLock(&lock, 5); }
Вопрос:((INT8*)lock)[1] = 1;
а также((INT8*)lock)[5] = 1;
магазины не находятся в том же месте, что и 64-битная загрузкаlock
, Тем не менее, каждый из них полностью содержится в этой загрузке, поэтому считается ли это «одним и тем же местом»? Кажется невозможным, чтобы процессор мог это сделать.
Как насчет((INT8*)lock)[0] = 1
? Адрес магазина тогда совпадает с адресом следующей загрузки. Являются ли эти операции «в том же месте», даже если предыдущий случай не был?
постскриптум обратите внимание, что вопрос не в коде C / Asm, а в поведении процессоров x86.