“энергозависимый” спецификатор и переупорядочения компилятора

Компилятор не может устранить или переупорядочить чтения/записи к a volatile- квалифицированные переменные.

Но что относительно случаев, где другие переменные присутствуют, который может или не может быть volatile- квалифицированный?

Сценарий 1

volatile int a;
volatile int b;

a = 1;
b = 2;
a = 3;
b = 4;

Компилятор может переупорядочить сначала и второе, или третий и четвертые присвоения?

Сценарий 2

volatile int a;
int b, c;

b = 1;
a = 1;
c = b;
a = 3;

Тот же вопрос, компилятор может переупорядочить сначала и второе, или третий и четвертые присвоения?

14
задан Alex B 29 March 2010 в 00:15
поделиться

3 ответа

Стандарт C ++ говорит (1.9 / 6):

Наблюдаемое поведение абстрактной машины - это ее последовательность чтения и записи в изменчивые данные и вызовов библиотечных функций ввода-вывода.

В сценарии 1 любое из предлагаемых вами изменений изменяет последовательность записи в изменчивые данные.

В сценарии 2 ни одно из предлагаемых вами изменений не меняет последовательность. Таким образом, они разрешены в соответствии с правилом «как если бы» (1.9 / 1):

... соответствующие реализации требуются для имитации (только) наблюдаемого поведения абстрактного машина ...

Чтобы определить, что это произошло, вам нужно проверить машинный код, использовать отладчик или спровоцировать неопределенное или неопределенное поведение, результат которого вам известен в вашей реализации. Например, реализация может гарантировать представление о том, что одновременно выполняющиеся потоки имеют одну и ту же память, но это выходит за рамки стандарта C ++.Таким образом, хотя стандарт может разрешить конкретное преобразование кода, конкретная реализация может исключить его на том основании, что он не знает, будет ли ваш код выполняться в многопоточной программе.

Если бы вы использовали наблюдаемое поведение, чтобы проверить, произошло ли переупорядочение или нет (например, распечатайте значения переменных в приведенном выше коде), то, конечно, это не будет разрешено стандартом.

12
ответ дан 1 December 2019 в 13:33
поделиться

Энергозависимость не является ограничением памяти. Присвоения B и C во фрагменте №2 можно исключить или выполнить в любое время. Почему вы хотите, чтобы объявления в №2 вызывали поведение №1?

2
ответ дан 1 December 2019 в 13:33
поделиться

Для сценария 1 компилятор не должен выполнять никаких переупорядочений, которые вы упомянули. Для сценария 2 ответ может зависеть от:

  • и от того, видны ли переменные b и c вне текущей функции (либо они не являются локальными, либо имеют свой адрес передал
  • , с кем вы разговариваете (очевидно, есть некоторые разногласия по поводу того, как строка volatile находится в C / C ++)
  • реализация вашего компилятора

Итак (смягчая мой первый ответ), я бы скажем, что если вы зависите от определенного поведения в сценарии 2, вам придется рассматривать его как непереносимый код, поведение которого на конкретной платформе будет определяться тем, что может указывать в документации реализации (и если в документации ничего не сказано об этом, то вам не повезло с гарантированным поведением.

из C99 5.1.2.3/2 «Выполнение программы»:

Доступ к изменчивому объекту, изменение объекта, изменение файла или вызов функции выполняющий любую из этих операций, все являются побочными эффектами, которые представляют собой изменения в состоянии среды выполнения. Оценка o е выражение может вызвать побочные эффекты. В определенных определенных точках последовательности выполнения, называемых точками последовательности, все побочные эффекты предыдущих оценок должны быть завершены, и никаких побочных эффектов последующих оценок не должно происходить.

...

(параграф 5) Наименьшие требования к соответствующей реализации:

  • В точках последовательности изменчивые объекты стабильны в том смысле, что предыдущие обращения завершены, а последующие обращения еще не произошли.

Вот немного того, что Херб Саттер должен сказать о требуемом поведении volatile доступа в C / C ++ (из « volatile vs. volatile http://www.ddj.com/hpc-high-performance-computing/212701484 ):

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

Что бы это ни стоило, Microsoft документирует следующее для ключевого слова C / C ++ volatile (как специфичного для Microsoft):

  • Запись в изменчивый объект (изменяемая запись) имеет семантику Release; ссылка на глобальный или статический объект, которая возникает перед записью в изменчивый объект в последовательности команд, произойдет до этой изменчивой записи в скомпилированном двоичном файле.

  • Чтение изменчивого объекта (изменчивое чтение) имеет семантику получения; ссылка на глобальный или статический объект, которая возникает после чтения энергозависимой памяти в последовательности команд, будет происходить после этого энергозависимого чтения в скомпилированном двоичном файле.

Это позволяет использовать энергозависимые объекты для блокировок и освобождения памяти в многопоточных приложениях.

4
ответ дан 1 December 2019 в 13:33
поделиться