Оптимизация доступа к общему массиву с временным квалификатором volatile

Мне было интересно, приведет ли в следующем сценарии временный квалификатор volatile к правильному поведению. Предположим, что ISR собирает значения в массиве, и как только будет собрано достаточное количество значений, он сигнализирует о готовности.

int array[10]; // observe no volatile here
int idx = 0;   // neither here
volatile bool ready = false; // but here

Здесь ISR является псевдокодом

ISR() {
  if (idx < 10)
     array[idx++] = ...;
  ready = (idx >= 10);
}

Предположим, что мы можем гарантировать, что array будет считываться только после ready, а доступ к элементам осуществляется с помощью определенного метода только:

int read(int idx) {
  // temporary volatile semantics
  volatile int *e = (volatile int*)(array + idx);
  return *e;
}

что, кажется, разрешено в соответствии с cpp-reference

Приведение энергонезависимого значения к изменчивому типу не имеет никакого эффекта. Чтобы получить доступ к энергонезависимому объекту с использованием семантики volatile, его адрес должен быть приведен к указателю на volatile, а затем доступ должен осуществляться через этот указатель.

Для полноты основная процедура делает следующее

void loop() {
   if (ready) {
     int val = read(0); // Read value 
     // do something with val.
   }
}

В таком сценарии я должен ожидать считывания правильных значений из array или изменчив в элементах массива, необходимых для гарантии того, что запись в массив из ISR() действительно выполняется в ОЗУ?

Обратите внимание, что Почему volatile необходимо в C? не уточняет, является ли в этот особый случай volatile необходим.


person cheind    schedule 28.10.2016    source источник
comment
volatile предотвращает только оптимизацию компилятора. Не требует доступа к переменным.   -  person LPs    schedule 28.10.2016
comment
Возможный дубликат Почему volatile необходимо в C?   -  person LPs    schedule 28.10.2016
comment
ISR = Подпрограмма обслуживания прерываний = в любом случае непереносимая. Проверьте документацию вашего компилятора.   -  person MSalters    schedule 28.10.2016


Ответы (1)


Запись в array[] осуществляется не через volatile, поэтому нельзя полагаться на наблюдаемое поведение. Да, компилятор должен выполнить некэшированное чтение array, но это только половина дела.

Вы говорите о порядке так, будто на него влияет volatile — это не так.

person MSalters    schedule 28.10.2016
comment
Но компилятор должен выполнить запись независимо от того, является ли массив изменчивым или нет. У компилятора нет возможности сделать вывод, что это записанное значение никогда не читается, поэтому я могу пропустить запись - он должен скорее вычесть обратное. Хотя я полагаю, что если массив записывается в одной единице перевода, а читается в другой, это может усложнить дело? Предположим, массив был объявлен как static, что гарантирует, что операции чтения/записи должны выполняться в одной и той же единице перевода? - person Lundin; 28.10.2016
comment
@Lundin именно то, о чем я думал / надеялся. Записи должны иметь место, и при принудительном чтении volatile позже (в некритическом по времени пути выполнения) все будет хорошо... - person cheind; 28.10.2016
comment
@Lundin: по этой логике компилятор также должен выполнять все операции чтения, он никак не может обнаружить, что было записано новое значение. Вы пытаетесь отговорить volatile. Что касается static, этого недостаточно. Компилятору нужно будет выполнить escape-анализ, чтобы увидеть, не происходит ли утечка указателя. - person MSalters; 28.10.2016
comment
Эм... нет? Чтение в этом случае обязательно должно выполняться из-за квалификаторов volatile. Если бы не это, компилятор, конечно, мог бы его пропустить. Сам вопрос здесь в том, станет ли запись обязательной из-за изменчивого чтения доступа. - person Lundin; 28.10.2016
comment
@Lundin: Аналогия заключалась в том, что если запись должна выполняться даже при отсутствии volatile, то чтение без volatile также должно выполняться. Но нет, чтение volatile не вызывает запись volatile хотя бы потому, что чтение volatile может быть в паре с другим volatile записать в другой ТУ. Компилятор не может предположить, что эти две операции являются парными. - person MSalters; 28.10.2016
comment
Возвращаясь к моему первоначальному комментарию, компилятор не может оптимизировать запись, если он не может сделать вывод, что переменная не используется. Это очень ясно изложено в стандарте C: реальная реализация не должна оценивать часть выражения, если она может сделать вывод, что его значение не используется и что не создаются необходимые побочные эффекты. Компилятор не может вывести здесь ничего подобного, поэтому, если бы он оптимизировал запись, это не соответствовало бы требованиям. Теперь, конечно, компилятор может быть тупым и не понимать, что ISR выполняется, и в этом случае код сломается по этой причине. - person Lundin; 28.10.2016