Я использую cmpxchg (сравнение и обмен) в архитектуре i686 для 32-битного сравнения и обмена следующим образом.
(Примечание редактора: в исходном 32-битном примере были ошибки, но вопрос не в этом. Я считаю, что эта версия безопасна, и в качестве бонуса корректно компилируется и для x86-64. Также обратите внимание, что встроенный ассемблер не требуется и не рекомендуется для этого; __atomic_compare_exchange_n
или более старый __sync_bool_compare_and_swap
работать для int32_t
или int64_t
на i486 и x86-64. Но этот вопрос касается того, чтобы сделать это с помощью встроенного ассемблера, если вы все еще хотите.)
// note that this function doesn't return the updated oldVal
static int CAS(int *ptr, int oldVal, int newVal)
{
unsigned char ret;
__asm__ __volatile__ (
" lock\n"
" cmpxchgl %[newval], %[mem]\n"
" sete %0\n"
: "=q" (ret), [mem] "+m" (*ptr), "+a" (oldVal)
: [newval]"r" (newVal)
: "memory"); // barrier for compiler reordering around this
return ret; // ZF result, 1 on success else 0
}
Что эквивалентно 64-разрядной архитектуре x86_64 для сравнения и замены
static int CAS(long *ptr, long oldVal, long newVal)
{
unsigned char ret;
// ?
return ret;
}
"+a"(oldval)
, потому чтоcmpxchg
обновляет EAX, если сравнение не удается и сохранение не выполнено. (Я думаю, что мы можем пропустить раннее затирание"+&a"
, потому что единственное, что нужно написать позже, этоret
. Нам не нужно читать обновленноеoldVal
из EAX внутри asm, поэтому, если компилятор не не нужен обновленныйoldVal
, это нормально, если он выделяетret
вal
(и на самом деле ваша функция не принимаетoldval
по ссылке. И, кстати, да, это может сломаться после встраивания, хотя автономная версия безопасна, потому что соглашения о вызовах.) - person Peter Cordes   schedule 15.04.2018ret==1
(CAS успешно). Простоreturn ret;
как нормальный человек. - person Peter Cordes   schedule 15.04.2018__sync_bool_compare_and_swap
или более новый__atomic_compare_exchange_n
решит проблему целая проблема для 32- или 64-битных целых чисел на i386 или x86-64 или любой другой архитектуре, которая вам нравится! С дополнительным преимуществом, позволяющим избежатьsete
/test
в цикле CAS и избежать дополнительной нагрузки, потому что эта дрянная версия не обновляетoldVal
по ссылке. gcc.gnu.org/wiki/DontUseInlineAsm. - person Peter Cordes   schedule 15.04.2018sete
? Интересно, что случилось с идентификатором пользователя оператора? Я не могу нажать на нее? Может быть, это вот этот парень? - person David Wohlferd   schedule 15.04.2018l
заставит код работать с 64-битным размером операнда, если аргументы изменены на 64-битные (как обычно для x86-64), и мы не можем переписать его в разумный вопрос, не аннулируя ответы. Я попробую. опубликуйте там хорошую версию. - person Peter Cordes   schedule 15.04.2018