В интервью мне сказали, что в C использование оператора ++ (скажем, i ++) является атомарной операцией, а выполнение, скажем, «i + = 1» - нет. Я думал, что эти операции точно такие же, когда дело касается безопасности потоков или атомарности. Я что-то упустил или это совсем другое?
Атомарность оператора приращения
Ответы (3)
Ерунда. Любой из них может быть или не быть атомарным, в зависимости от типа данных, архитектуры и, возможно, компилятора (стандарт не дает гарантий относительно атомарности в целом, если вы не используете атомарность C11), но я не вижу ничего хорошая причина думать, что в общем случае i++
будет атомарным, а i += 1
- нет. Очень вероятно, что они фактически генерируют один и тот же код в контексте, где результат выражения не используется.
Операторы * i++;
и i += 1;
эквивалентны в C. Ни один из них не может быть атомарным.
В частности, приращения переменных, превышающих размер системного слова (например, 64-разрядные переменные в 32-разрядных системах), почти всегда не атомарны, поскольку атомарное приращение такой переменной часто требует явной блокировки. Кроме того, некоторые архитектуры не поддерживают прямое увеличение переменных в памяти. (То есть они требуют явной последовательности загрузки / изменения / сохранения.) Эти архитектуры не могут атомарно изменять любую переменную без блокировки.
* при рассмотрении как отдельных операторов, а не выражений
++i
определяется как i += 1
- person M.M; 16.01.2015
интервьюер ошибается.
Я скомпилировал две функции с помощью gcc-4.8.2 -O2
-S
void increment1(int *a) {
*a += 1;
}
void increment2(int *a) {
(*a)++;
}
оба генерируют ровно the same
сборки
increment1:
.LFB0:
.cfi_startproc
addl $1, (%rdi)
ret
.cfi_endproc
.LFE0:
.size increment1, .-increment1
.p2align 4,,15
.globl increment2
.type increment2, @function
increment2:
.LFB1:
.cfi_startproc
addl $1, (%rdi)
ret
.cfi_endproc
Но в контексте более точного технического анализа, оба они atomic write
, что означает, что он не дает результата MAD. если вы используете переменную int64_t в 32-разрядной или менее разрядной среде ЦП, 64-разрядная модификация приведет к многократной операции записи. Без замка не может быть atomic write
.
Вы можете использовать операцию __sync_fetch_and_add(&a, 1)
для атомарного приращения в среде gcc.
++i
иi += 1
очень похоже (они одинаковы, потому что результатом выражения является увеличивающееся значение). Это отличается отi++
, где результатом выражения является значение до приращения. Как полные утверждения, эти три эквивалентны. Ни один из них не может быть атомарным. - person Jonathan Leffler   schedule 16.01.2015i += 1
атомарно? Это не дубликат, потому что он не упоминаетi++
или++i
, но это тесно связано. - person Jonathan Leffler   schedule 16.01.2015