как я могу преобразовать неатомарную операцию в атомарную - PullRequest
5 голосов
/ 10 июля 2011

Я пытаюсь понять атомарные и неатомарные операции. По отношению к операционной системе, а также по отношению к C. Согласно странице википедии здесь

Рассмотрим простой счетчик, который отличаетсяпроцессы могут увеличиваться.
Неатомарная

Наивная неатомарная реализация:
читает значение в ячейке памяти;
добавляет единицу к значению;
записывает новое значение обратно в ячейку памяти.

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

Как вышеописанная операция может быть сделана в форме атмо.Мое понимание атомарной операции состоит в том, что любая вещь, которая выполняется без прерывания, является атомной.Так, например,

int b=1000;
  b+=1000;

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

Ответы [ 5 ]

4 голосов
/ 10 июля 2011

C99 не может сделать переменные атомарными по отношению к другим потокам.C99 не имеет понятия о нескольких потоках исполнения.Таким образом, вам нужно использовать специфичные для компилятора расширения и / или инструкции уровня CPU для достижения атомарности.

Следующий стандарт C, в настоящее время известный как C1x, будет включать в себя атомарные операции.

Evenтогда просто атомарность просто гарантирует, что операция является атомарной, она не гарантирует, когда эта операция станет видимой для других процессоров.Чтобы обеспечить гарантии видимости, в C99 вам необходимо изучить модель памяти вашего ЦП и, возможно, использовать специальный вид инструкций ЦП, известный как заборы или барьеры памяти.Вы также должны сообщить об этом компилятору, используя какой-то специфический для компилятора барьер.C1x определяет несколько порядков памяти, и когда вы используете атомарную операцию, вы можете решить, какой порядок памяти использовать.

Некоторые примеры:

/* NOT atomic */
b += 1000;

/* GCC-extension, only in newish GCCs 
 *   requirements on b's loads are CPU-specific
 */
__sync_add_and_fetch(&b, 1000);

/* GCC-extension + x86-assembly, 
 *   b should be aligned to its size (natural alignment), 
 *   or loads will not be atomic
 */
__asm__ __volatile__("lock add $1000, %0" : "+r"(b));


/* C1x */
#include <stdatomic.h>
atomic_int b = ATOMIC_INIT(1000);
int r = atomic_fetch_add(&b, 1000) + 1000;

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

3 голосов
/ 10 июля 2011
int b = 1000;
b+=1000;

превращается в несколько операторов на уровне инструкции. По крайней мере, подготовка регистра или памяти, присвоение 1000, затем получение содержимого этого регистра / памяти, добавление 1000 к содержимому и переназначение нового значения (2000) этому регистру. Без блокировки ОС может приостановить процесс / поток в любой точке этой операции. Кроме того, в многопроцессорных системах другой процессор может получить доступ к этой памяти (в данном случае это не регистр) во время выполнения операции.

Когда вы берете блокировку (как вы бы сделали это атомарным), вы, в частности, информируете ОС, что приостановка этого процесса / потока не разрешена, и что к этой памяти не должен обращаться другие процессы.

Теперь приведенный выше код, вероятно, будет оптимизирован компилятором для простого назначения 2000 в ячейку памяти для b, но я игнорирую это для целей этого ответа.

3 голосов
/ 10 июля 2011

b+=1000 скомпилирован во всех известных мне системах с несколькими инструкциями.Таким образом, он не является атомарным.

Даже b=1000 может быть неатомарным, хотя вы должны усердно работать, чтобы создать ситуацию, когда это не атомарно.

На самом деле C не имеет понятия о потокахи поэтому в C. нет ничего атомарного. Вы должны полагаться на детали реализации вашего компилятора и инструментов.

0 голосов
/ 10 июля 2011

Так что я хочу понять, что атомность отличается, когда это приходит к языкам программирования, чем Операционные системы?

Я немного смущен этим вопросом. Что ты конкретно имеешь ввиду? Концепция атомарности одинакова как в проге. языки и ОС.

Что касается атомарности и языка, вот, например, ссылка на атомарность в JAVA, которая может дать вам другую точку зрения: Какие операции в Java считаются атомарными?

0 голосов
/ 10 июля 2011

Вышеуказанные операторы не являются атомарными, потому что они становятся инструкцией перемещения для загрузки b в регистр (если это не так), затем добавляют 1000 к нему и сохраняют обратно в память.Многие наборы команд допускают атомарность за счет атомарного приращения, проще всего быть x86 с блокировкой addl dest, src;некоторые другие наборы команд используют cmpxchg для достижения того же результата.

...