О гарантии атомности в C - PullRequest
       16

О гарантии атомности в C

2 голосов
/ 18 сентября 2009

На компьютерах с архитектурой x86 инструкции типа inc, addl не являются атомарными, и в среде SMP их использование небезопасно без префикса блокировки. Но в среде UP это безопасно, поскольку inc, addl и другие простые инструкции не будут прерваны.

Моя проблема в том, что, учитывая оператор уровня C, такой как

x = x + 1;

Существуют ли какие-либо гарантии того, что компилятор C всегда будет использовать инструкции UP-safe, такие как

incl %eax

но не те инструкции по безопасности потоков (например, реализация оператора C в нескольких инструкциях, которые могут быть прерваны переключением контекста) даже в среде UP?

Ответы [ 8 ]

6 голосов
/ 18 сентября 2009

номер

Вы можете использовать «volatile», который запрещает компилятору удерживать x во временном регистре, и для большинства целей это будет иметь ожидаемый эффект. Но это не гарантировано.

Чтобы быть в безопасности, вы должны использовать встроенный ассемблер или, если вам нужно оставаться переносимым, инкапсулировать приращение с мьютексами.

4 голосов
/ 19 сентября 2009

В последних версиях GCC есть встроенные функции __sync_xxx, которые делают именно то, что вы хотите.

Вместо записи:

x + = 1;

напишите это:

__ sync_fetch_and_add (& x, 1);

И gcc позаботится о том, чтобы это было скомпилировано в атомарный код операции. В настоящее время это поддерживается в большинстве важных арок.

http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html

Первоначально он был основан на рекомендациях Intel для C для ia64, но теперь нашел способ использовать gcc для многих других архитектур. Так что это даже немного портативно.

4 голосов
/ 18 сентября 2009

Абсолютно нет гарантии того, что "x - x + 1" будет компилироваться в безопасные для прерывания инструкции на любой платформе, включая x86. Вполне может быть, что это безопасно для конкретного компилятора и конкретной архитектуры процессора, но это не предусмотрено стандартами вообще, и стандарт - единственная гарантия, которую вы получаете.

Вы не можете считать что-либо безопасным, исходя из того, что, по вашему мнению, будет компилироваться. Даже если определенный компилятор / архитектура заявляет, что это так, полагаться на него очень плохо, так как это снижает переносимость. Другие компиляторы, архитектуры или даже более поздние версии на том же компиляторе и архитектуре могут довольно легко нарушить ваш код.

Вполне возможно, что x = x + 1 может скомпилироваться в произвольную последовательность, такую ​​как:

load r0,[x]  ; load memory into reg 0
incr r0      ; increment reg 0
stor [x],r0  ; store reg 0 back to memory

на процессоре без инструкций увеличения памяти. Или он может быть умным и скомпилировать его в:

lock         ; disable task switching (interrupts)
load r0,[x]  ; load memory into reg 0
incr r0      ; increment reg 0
stor [x],r0  ; store reg 0 back to memory
unlock       ; enable task switching (interrupts)

где lock отключает, а unlock разрешает прерывания. Но даже в этом случае это может быть поточно-ориентированным в архитектуре, в которой более одного из этих процессоров совместно используют память (lock может отключать прерывания только для одного процессора), как вы уже заявили.

Сам язык (или библиотеки для него, если он не встроен в язык) будет обеспечивать поточно-ориентированные конструкции, и вы должны использовать их, а не зависеть от вашего понимания (или, возможно, неправильного понимания) того, какой машинный код будет сгенерирован.

Такие вещи, как Java synchronized и pthread_mutex_lock() (доступны для C в некоторых ОС) - это то, что вы хотите изучить.

4 голосов
/ 18 сентября 2009

Если вы используете GLib, у них есть макросы для int и атомарные операции с указателями.

http://library.gnome.org/devel/glib/stable/glib-Atomic-Operations.html

1 голос
/ 18 сентября 2009

Существуют ли какие-либо гарантии того, что компилятор C всегда будет использовать инструкции UP-safe

Не в стандарте C. Но ваш компилятор / стандартная библиотека может предоставить вам специальные типы или определенные гарантии.

Этот gcc doc может соответствовать тому, что вам нужно.

0 голосов
/ 18 сентября 2009

В любом случае беспокоиться только о x86 - ужасно непереносимое кодирование. Это одна из тех, казалось бы, небольших задач по кодированию, которая сама по себе оказывается проектом. Найдите существующий библиотечный проект, который решает такую ​​проблему для широкого спектра платформ, и используйте его. GLib, кажется, один из того, что говорит kaizer.se.

0 голосов
/ 18 сентября 2009

Компилятор C может реализовывать оператор типа x = x + 1 в нескольких инструкциях.
Вы можете использовать ключевое слово register , чтобы подсказывать компилятору использовать регистр вместо памяти, но компилятор free игнорирует его.

Я предлагаю использовать определенные процедуры блокировки ОС, такие как Функция InterlockedIncrement в Windows.

0 голосов
/ 18 сентября 2009

Полагаю, вам нужно прибегнуть к библиотекам, ориентированным на SMP, или свернуть свой собственный встроенный код ассемблера.

...