Давайте получим следующее простое определение мьютекса:
class Mutex {
private:
bool lock;
public:
void acquire();
void release();
Mutex() {
lock = 0;
}
};
И следующее acquire()
Реализация функции (с использованием операций сравнения и обмена):
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 и их эквивалентах на других архитектурах)? Какое решение будет использовать компилятор в этом случае?
Постскриптум — я использовал gcc 8.2 для создания ассемблерного кода, и вот __atomic_
встроенные функции: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
Задача ещё не решена.
Других решений пока нет …