Как описано в других публикациях, без какой-либо квалификации volatile
или std::atomic
, компилятор и / или процессор могут переупорядочивать последовательность операторов (например, присваивания):
// this code
int a = 2;
int b = 3;
int c = a;
b = c;
// could be re-ordered/re-written as the following by the compiler/processor
int c = 2;
int a = c;
int b = a;
Тем не менее, условные и управляющие операторы (например, if
, while
, for
, switch
, goto
) также могут быть переупорядочены, или они по сути считаются «забором памяти» ?
int* a = &previously_defined_int;
int b = *a;
if (a == some_predefined_ptr)
{
a = some_other_predefined_ptr; // is this guaranteed to occur after "int b = *a"?
}
Если приведенные выше операторы можно переупорядочить (например, сохранить a
во временном регистре, обновить a
, а затем заполнить b
путем отмены ссылки на "старый" a
во временном регистре), который, я полагаю, мог бы быть при том же поведении «абстрактной машины» в однопоточном окружении, тогда почему нет проблем при использовании блокировок / мьютексов?
bool volatile locked = false; // assume on given implementation, "locked" reads/writes occur in 1 CPU instruction
// volatile so that compiler doesn't optimize out
void thread1(void)
{
while (locked) {}
locked = true;
// do thread1 things // couldn't these be re-ordered in front of "locked = true"?
locked = false;
}
void thread2(void)
{
while (locked) {}
locked = true;
// do thread2 things // couldn't these be re-ordered in front of "locked = true"?
locked = false;
}
Даже если использовался std::atomic
, операторы non-atomi c можно по-прежнему переупорядочивать вокруг операторов atomi c, так что это не помогло бы гарантировать, что операторы "критической секции" (т.е. "do threadX вещи") ) содержались в их предполагаемом критическом разделе (то есть между блокировкой / разблокировкой).
Редактировать: На самом деле, я понимаю, что пример блокировки на самом деле не имеет ничего общего с вопросом оператора условия / управления Я попросил. Тем не менее, было бы неплохо получить разъяснения по обоим задаваемым вопросам:
- переупорядочение внутри и вокруг условных / контрольных операторов
- - это блокировки / мьютексы приведенной выше формы надежный?
- Пока что ответ из комментариев: «Нет, потому что между проверкой while () и получением блокировки есть условие гонки», но кроме этого, мне также интересно узнать о расположении потока код функции вне «критической секции»