Считаю, что речь идёт про контекст взаимодействия с соседними тредами или даже процессами.
Даже если речь идёт про банальные int — нет.
Никто не мешает компилятору прочитать значение, выполнить десяток выражений (не включая неизвестные компилятору функции) и записать изменённое только после этого.
Volatile сокращает это до одного оператора, но даже в нём может быть чтение отдельно от записи, смотря кому как удобнее. И даже при кодировании во что-то типа "add var, 1" с другого процессора могут влезть.
Используйте или std::atomic (C++), или всякие _sync_fetch_and_add (GCC), или InterlockedAdd (Windows), или любой другой аналог.
Здравствуйте, Mr.Delphist, Вы писали:
MD>Здравствуйте, Hard_Club, Вы писали:
MD>Зависит от MD>* типа данных MD>* текущей платформы
Это да.
MD>Например, инкремент int64 неатомарен на x86, но атомарен на x64.
Не могу согласиться.
1. Нет никакой гарантии, что оно скомпилируется в одну команду.
2. Нет никакой гарантии, что эта команда вызовется с префиксом lock; а если нет — содержимое памяти может быть изменено соседом между чтением и записью (напоминаю, что уже лет 7 процессоры двухядерные и выше даже на десктопах).
Здравствуйте, netch80, Вы писали:
N>Не могу согласиться. N>1. Нет никакой гарантии, что оно скомпилируется в одну команду. N>2. Нет никакой гарантии, что эта команда вызовется с префиксом lock; а если нет — содержимое памяти может быть изменено соседом между чтением и записью (напоминаю, что уже лет 7 процессоры двухядерные и выше даже на десктопах).
Если нет информации, является ли операция атомарной, нужно исходить из того, что нет.
Для выполнения инкремента/декремента переменной процессору нужно выполнить как минимум три команды:
1. Загрузить значение из памяти в регистр
2. инкрементировать/декрементировать содержимое регистра
3. положить результат обратно в память.
В многопроцессорной/многопоточной среде другой поток может вклиниться между этими командами и изменить значение переменной в памяти.
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, netch80, Вы писали: U>популярные компиляторы типа gcc, VS дают некие гарантии по атомарному чтению\записи 32/64 битных чисел U>http://msdn.microsoft.com/en-us/library/ms684122(VS.85).aspx
так это он говорит, что, например, при чтении 32битного значения, которое параллельно изменяется другим потоком, мы не прочитаем первые 8бит старых, а оставшиеся 24бита новых
В этом смысле да, чтение и запись атомарны даже без лока
Нет, они в общем случае не атомарны, в том смысле, что между увеличением значения переменной и её записью может попасть операция над ней из другого потока.
Здравствуйте, uzhas, Вы писали:
N>>Не могу согласиться. N>>1. Нет никакой гарантии, что оно скомпилируется в одну команду. N>>2. Нет никакой гарантии, что эта команда вызовется с префиксом lock; а если нет — содержимое памяти может быть изменено соседом между чтением и записью (напоминаю, что уже лет 7 процессоры двухядерные и выше даже на десктопах).
U>популярные компиляторы типа gcc, VS дают некие гарантии по атомарному чтению\записи 32/64 битных чисел U>http://msdn.microsoft.com/en-us/library/ms684122(VS.85).aspx
1) при правильном выравнивании
2) раздельно на чтение и запись. а инкремент — это две операции
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, uzhas, Вы писали:
N>>>Не могу согласиться. N>>>1. Нет никакой гарантии, что оно скомпилируется в одну команду. N>>>2. Нет никакой гарантии, что эта команда вызовется с префиксом lock; а если нет — содержимое памяти может быть изменено соседом между чтением и записью (напоминаю, что уже лет 7 процессоры двухядерные и выше даже на десктопах).
U>>популярные компиляторы типа gcc, VS дают некие гарантии по атомарному чтению\записи 32/64 битных чисел U>>http://msdn.microsoft.com/en-us/library/ms684122(VS.85).aspx
N>1) при правильном выравнивании N>2) раздельно на чтение и запись. а инкремент — это две операции
Здравствуйте, Hard_Club, Вы писали:
U>>>популярные компиляторы типа gcc, VS дают некие гарантии по атомарному чтению\записи 32/64 битных чисел U>>>http://msdn.microsoft.com/en-us/library/ms684122(VS.85).aspx
N>>1) при правильном выравнивании N>>2) раздельно на чтение и запись. а инкремент — это две операции
H_C>А что при неправильном не гарантирует?
Нет.
Например, длина кэш-строки 16, а данное типа int размещено по адресу 78.
Будет сделано два раздельных чтения: одно для 64-79 с выборкой 78-79 для младшей половины этого int, второе для 80-95 (80-81 — старшая половина того int). Между ними может произойти вмешательство соседа с модификацией части данных.
Здравствуйте, dead0k, Вы писали:
D>Здравствуйте, uzhas, Вы писали:
U>>Здравствуйте, netch80, Вы писали: U>>популярные компиляторы типа gcc, VS дают некие гарантии по атомарному чтению\записи 32/64 битных чисел U>>http://msdn.microsoft.com/en-us/library/ms684122(VS.85).aspx D>так это он говорит, что, например, при чтении 32битного значения, которое параллельно изменяется другим потоком, мы не прочитаем первые 8бит старых, а оставшиеся 24бита новых D>В этом смысле да, чтение и запись атомарны даже без лока
Видимо, тут надо уточнить у топик-стартера, что именно он понимает под атомарностью. Т.к. я вопрос понял именно в этом ключе — когда даже при конкурентной записи/чтении не будет сборной солянки, когда переменная X содержит часть байтов от одной операции и часть — от другой.
MD>Видимо, тут надо уточнить у топик-стартера, что именно он понимает под атомарностью. Т.к. я вопрос понял именно в этом ключе — когда даже при конкурентной записи/чтении не будет сборной солянки, когда переменная X содержит часть байтов от одной операции и часть — от другой.
Здравствуйте, Hard_Club, Вы писали:
H_C>Я вообще задавал вопрос в общем случае.
Тем более, в общем случае. Нет, не атомарны!
Не нужно искать оправдание тому, что в коде написано ++RefCount без явной синхронизации. (Переменная является разделяемым ресурсом). Это может быть хак, невнимательность или незнание. Для проекта любой из вариантов зло. Явно обозначай свои намерения: в случае разделяемых среди потоков данных — применяй объекты синхронизации.
Ты можешь не точно знать, что там под капотом, какого размера линии кеша, что такое инструкция lock, какие особенности smp на архитектуре, но обязан выполнять фундаментальные положения программирования, повторюсь: разделяемые ресурсы =>> явная синхронизация. Хаки — это даже не второй уровень оптимизации, а намного более тонкая материя, достояная отдельного комментария в коде
Здравствуйте, alexku, Вы писали:
A>Если нет информации, является ли операция атомарной, нужно исходить из того, что нет.
Верно.
A>Для выполнения инкремента/декремента переменной процессору нужно выполнить как минимум три команды: A>1. Загрузить значение из памяти в регистр A>2. инкрементировать/декрементировать содержимое регистра A>3. положить результат обратно в память.
Строго говоря, рассуждая на уровне ЯВУ, мы вообще не имеем права говорить ни о регистрах, ни о памяти, так как неизвестна архитектура процессора и система команд.
Здравствуйте, dead0k, Вы писали:
D>так это он говорит, что, например, при чтении 32битного значения, которое параллельно изменяется другим потоком, мы не прочитаем первые 8бит старых, а оставшиеся 24бита новых D>В этом смысле да, чтение и запись атомарны даже без лока
Выравнивание нужно поставить по границе слова, тогда чтение/запись занимает один такт.