Здравствуйте, MaximE, Вы писали:
ME>Использование любого примитива синхронизации в POSIX и win32 является вызовом ф-ции. Вызов ф-ции — sequence point. Если у тебя уже есть sequence points вокруг защищаемых данных, зачем тогда volatile?
Абсолютной необходимости в примитивах синхронизации нет. Если один процесс записывает значения в некоторую ячейку общей памяти, а другой их оттуда читает, и доступ к ячейке на всех поддерживаемых платформах гарантированно атомарный — какой смысл в дополнительных примитивах? Достаточно лишь указать компилятору, что с объектом нужно вести себя более аккуратно, что и делает volatile.
Например, в Windows MME в описателе звукового буфера есть флажок WHDR_DONE, означающий, что драйвер завершил обработку буфера. Можно, конечно, заказать специфическое уведомление, но можно и просто опрашивать этот флажок время от времени. Что запретит компилятору перечитывать его из памяти, если весь описатель не будет объявлен с volatile?
>> Функции используются только для изменения volatile-переменных. Чтение их значений может происходить в параллельных потоках без каких-либо функций.
ME>Это так только по случайному стечению обстоятельств на IA32.
Почему по случайному? Еще не так давно подавляющее большинство платформ работало именно так.
ME> volatile имеет влияние лишь на код, генерируемый компилятором. На переупорядочивание инструкций процессором он не имеет никакого влияния.
А зачем? Назначение volatile — влиять именно на код. Соответственно, процессор своими средствами обеспечивает определенность вычислений.
ME> Именно по этой причине на всех современных RISC процессорах, а также на IA64, тебе придется использовать барьеры памяти чтобы прочитать актуальное значение.
Именно этим может и заниматься компилятор, обрабатывая volatile.
>> ME> После sequence points, компилятор обязан перечитывать значения переменных из памяти, неважно, volatile ли, const ли, или это переменная без cv-квалификатора
>>
>> С чего бы он вдруг стал обязан? Компилятор обязан лишь обеспечить последовательное выполнение заданных действий в рамках одного потока исполнения. Для взаимодействия с "внешними" процессами и существует volatile.
ME>С тем, что состояние программы после sequence point is indeterminate.
Из чего это следует?
>> Простейший пример:
>>
>> >> void f (int &a, int &b) {
>> if (!a) {
>> b = a;
>> }
>> }
>>
>>
>> При включенной оптимизации многие компиляторы (например, VC++ 6.0) сгенерируют только один опрос переменной a — в проверке условия. Для присваивания будет сгенерирован явный нуль.
ME>Здесь именно простейший пример: нет вызовов ф-ций, компилятор видит весь контекст и плевал на sequence points. Добавим вызов ф-ции.
А давай вместо вызова функции добавим модификацию объекта — например, введем переменную
c и сделаем ей инкремент:
int c = b;
if (!a) {
c++;
b = a;
}
return c;
Модификация объекта, согласно стандарту, есть sequence point. А по соглашениям MS любой оператор также является SP, и условие в if является ею же. Однако это не мешает компилятору по-прежнему использовать константу-нуль.
Я вообще не понимаю, почему ты относишь значение объекта к side effects.
ME>Мой point: volatile бесполезен (и даже вреден) для multithreading, барьеры нужны по-любому.
Где в C++ барьеры? Их там нет — они реализуются средствами платформы. Наличие барьеров без volatile не гарантирует правильной работы. Наличие volatile без барьеров — тоже не гарантирует. volatile обеспечивает поддержку со стороны языка, барьер — со стороны аппаратуры. Зачем, по-твоему, вообще существует volatile? Именно для урезания вольностей оптимизатора в отношении состояния объекта.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>