Давайте получим следующее простое определение мьютекса:
class Mutex {
private:
bool lock;
public:
void acquire();
void release();
Mutex() {
lock = 0;
}
};
И следующую реализацию acquire()
func (с использованием операций сравнения и обмена):
void Mutex::acquire() {
bool oldValue;
__atomic_load(&lock, &oldValue, 0);
bool newValue = true;
while (!__atomic_compare_exchange_n(&lock, &oldValue, newValue, true, 0, 0)) {
sched_yield();
}
}
В этомВ этом случае мы получим следующий код сборки:
movzx eax, BYTE PTR [rsp+15]
lock cmpxchg BYTE PTR [rbx], bpl
je .L9
Или в случае использования __atomic_test_and_set
:
void Mutex::acquire() {
while (__atomic_test_and_set(&lock, 0)) {
sched_yield();
}
}
Получим следующий код сборки:
mov eax, ebp
xchg al, BYTE PTR [rbx]
test al, al
jne .L6
Но, что, если у нас нет аппаратной поддержки атомарных операций Test-and-Set и CAS-операций (xchg
и lock cmpxchg
на x86 и их эквивалентах на других архитектурах)? Какое решение будет использовать компилятор в этом случае?
PS - я использовал gcc 8.2 для создания ассемблерного кода, а вот __atomic_
встроенные функции: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html