LINUX.ORG.RU

Присваивание переменных - насколько атомарно?


0

0

Вот возник такой вопрос. Интересует чисто теоретически - на практике применять не буду. =)

Допустим, есть один поток, который изменяет переменную, и есть один поток, который ее считывает. Насколько безопасно это делать без мьютексов?

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

Я правильно рассуждаю, или все не так просто?

P.S.: про volatile я знаю. Насколько я понимаю, он запрещает только "кешировать" значение int'а в регистре между несколькими обращениями к переменной и ничего больше. Причем, также насколько я знаю, при вызове функции компилятор "сбрасывает" подобные кэши, исходя из предположения, что данная функция может как-то изменить данную переменную (просто присвоив значение, если она глобальная или через указатель, если она локальная).

А тут я прав? =)


без синхронизации по-моему нифига не безопасно

kto_tama ★★★★★
()

> Вроде бы, на 32-ух разрядных машинах int укладывается в один регистр, а значит, насколько я понимаю, его запись атомарна,

Чтение значения переменной из памяти, изменение, запись в память. Три разных операциию. О какой атомарности может идти речь?

И регистры тут не причем - они не шарятся между разными потоками, шарится как раз память.

Spectr ★★★
()
Ответ на: комментарий от Spectr

> Чтение значения переменной из памяти, изменение, запись в память. Три разных операциию. О какой атомарности может идти речь?

присваивание != изменение

// wbr

klalafuda ★☆☆
()

Изменение переменной не атомарно.
Ключевое слово volatile указывает компилятору, что объект или переменная могут быть изменены извне программы, для того, чтобы компилятор не заоптимизировал ее вусмерть.

tzukko
()
Ответ на: комментарий от tzukko

> Присваивание может быть и атомарным, а может и не быть.

факт. но все-таки mov eax, [addr] - это атомарная операция. по крайней мере на i386/EMT64.

// wbr

klalafuda ★☆☆
()

> Допустим, есть один поток, который изменяет переменную, и есть один поток, который ее считывает. Насколько безопасно это делать без мьютексов?

Нинасколько. Если тебе, конечно, не все равно, что будет считано.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

> Нинасколько. Если тебе, конечно, не все равно, что будет считано.

7.1.1 Guaranteed Atomic Operations
The Intel486 processor (and newer processors since) guarantees that the following
basic memory operations will always be carried out atomically:
• Reading or writing a byte
• Reading or writing a word aligned on a 16-bit boundary
• Reading or writing a doubleword aligned on a 32-bit boundary
The Pentium processor (and newer processors since) guarantees that the following
additional memory operations will always be carried out atomically:
• Reading or writing a quadword aligned on a 64-bit boundary
• 16-bit accesses to uncached memory locations that fit within a 32-bit data bus
The P6 family processors (and newer processors since) guarantee that the following
additional memory operation will always be carried out atomically:
• Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit within a cache
line
Accesses to cacheable memory that are split across bus widths, cache lines, and
page boundaries are not guaranteed to be atomic by the Intel Core 2 Duo, Intel Core
Duo, Pentium M, Pentium 4, Intel Xeon, P6 family, Pentium, and Intel486 processors.
The Intel Core 2 Duo, Intel Core Duo, Pentium M, Pentium 4, Intel Xeon, and P6
family processors provide bus control signals that permit external memory
subsystems to make split accesses atomic; however, nonaligned data accesses will
seriously impact the performance of the processor and should be avoided.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda


ps: Intel® 64 and IA-32 Architectures
Software Developer’s Manual
Volume 3A:
System Programming Guide, Part 1

// wbr

klalafuda ★☆☆
()

> Допустим, есть один поток, который изменяет переменную, и есть один поток, который ее считывает. Насколько безопасно это делать без мьютексов?

А какая разница в данном случае, атомарно ли изменение этой переменной? Веть твой поток, который читает переменную, должен и дальше что-то делать (скажем сам её изменить или ещё что-то). И пока он возьмётся за эти действия, другой поток может снова эту переменную изменить. Получится, что читающий поток будет действовать с "неверными данными".

lv ★★
()

> Допустим, есть один поток, который изменяет переменную, и есть один поток, который 
ее считывает. Насколько безопасно это делать без мьютексов?

Абсолютно небезопасно на многоядерных/многопроцессорных системах :) Еще один источник опасностей -- предвыборка данных ядрами, и возможность рассинхронизаци мнения ядер, о том, что в памяти. Скажем считал один core переменную, запустил ее значение в pipeline, и колбасит, разбив операцию на 2-3 десятка микроопераций, а тут другой core эту переменную поменял. Нужно что? оповестить  все остальные ядра, что память по такому адресу была поменяна, и все те, кто ее закешировал и заграбастал в pipeline должны обновить кеш и сбросить конвеер. Без средств синхронизации это бывает не всегда, вот и выходит задница.

armag
()

в матрице сменили программу(с)

dilmah ★★★★★
()

На столько, на сколько это невозможно.

balodja ★★★
()

на некоторых SMP системах можешь получить SIGBUS если будешь на это расчитывать...

sergej ★★★★★
()
Ответ на: комментарий от armag

> Абсолютно небезопасно на многоядерных/многопроцессорных системах :) Еще один источник опасностей -- предвыборка данных ядрами, и возможность рассинхронизаци мнения ядер, о том, что в памяти. Скажем считал один core переменную, запустил ее значение в pipeline, и колбасит, разбив операцию на 2-3 десятка микроопераций, а тут другой core эту переменную поменял. Нужно что? оповестить все остальные ядра, что память по такому адресу была поменяна, и все те, кто ее закешировал и заграбастал в pipeline должны обновить кеш и сбросить конвеер. Без средств синхронизации это бывает не всегда, вот и выходит задница.

Т.е. черевато это например тем, что если например весь цикл:

while (!flag) {}

всосется в конвеер, на тот момент, когда flag был ==0, то он так и останется крутится, даже после выставления flag в 1.

armag
()
Ответ на: комментарий от mv

> Если это дефолтная платформа (x86), то прочитать про когерентный кэш.

a pipeline?

armag
()
Ответ на: комментарий от lv

>А какая разница в данном случае, атомарно ли изменение этой переменной?

Весь вопрос был в том, атомарно или нет. Как уже построенна программа, другое дело. Грубо говоря, было в памяти число 10, один поток пишет туда число 11, а другой в это время читает это число. Вопрос был, гарантированно, что прочитается число 10 или 11, а не что-нибудь совсем левое.

А сам алгоритм взаиводействия может быть такой. Один поток делает определенные операции и инкрементирует общую переменную. Другой поток читает эту переменную, если она отличается от его внутренней, то он делает определенные действия и инкрементирует внутренную переменную. Это так к вопросу о действии с неверными данными.

mky ★★★★★
()
Ответ на: комментарий от armag

> Т.е. черевато это например тем, что если например весь цикл:
>
> while (!flag) {}
>
> всосется в конвеер, на тот момент, когда flag был ==0, то он
> так и  останется крутится, даже после выставления flag в 1.

не, это неправда ;) и вообще pipeline тут не при чем.
вот компилятор может этот код поменять на что-нибудь
вроде

    if (!flag) for (;;);

(если flag не volatile).

присваивание слова всегда атомарно. любой другой процесс
прочитает либо старое, либо новое значение, но никак не
"что-то между".

во всяком случае на том железе, где linux может работать.

если мы _только_ считываем слово, никакая синхронизация
нам не нужна, пользы ровно 0.

idle ★★★★★
()

Всем спасибо за ответы. Очень интересно было почитать.

riYu
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.