Перейти к содержанию

Си++/Разные вопросы

Материал из Викиучебника — открытых книг для открытого мира

Разные вопросы

[править]

В чём великий смысл «volatile»?

[править]

Напишем следующую программу:

int x = 0;
int main () {
  while (x < 10) {
  }
}

Как несложно заметить, она работает вечно. Более того, она полностью загружает весь ваш процессор очень сложными вычислениями…

Что с ней сделает хороший компилятор? Он заметит, что значение переменной «x» внутри цикла не изменяется. Поэтому он просто не будет каждый раз читать значение «x» из памяти и сравнивать его с 10. Зачем? Какое значение «x» было при входе в цикл, таким оно и останется. Поэтому он превратит ваш код в нечто похожее на:

int x = 0;
int main () {
  if (x < 10) {
    while (1) {
    }
  }
}

Замечательно! Но предположим, что есть ещё кто-то. Этот кто-то вашу переменную «x» каждую секунду увеличивает на единицу. Поэтому ваш первоначальный код на самом деле должен был через 10 секунд завершаться! Но компилятор-то этого не знал, и сделал из неё бесконечный цикл.

Для того, чтобы сообщить компилятору о присутствии кого-то, и служит ключевое слово «volatile». Если переписать пример в виде:

volatile int x = 0;
int main () {
  while (x < 10) {
  }
}

то компилятор при каждом обращении к «x» будет честно заново считывать её из памяти. Ведь её значение могли изменить некие тёмные силы.

Спецификатор volatile подавляет оптимизацию common subexpression elimination (исключение общих подвыражений), заставляя компилятор действительно читать значение из памяти каждый раз.

Что касается правил языка, то снятие спецификатора volatile невозможно без написания явного преобразования к типу (в этом volatile аналогичен const).

NB: Хорошим примером такого рода тёмных сил является другой процесс, имеющий с вашим общую память. Как правило, практическая нужда в volatile возникает только при использовании многонитевости.

NB1: Вообще говоря, описанная в этом параграфе 100%-я загрузка ядра процессора бессмысленной деятельностью является хорошим примером дурного тона в программировании. Используйте имеющиеся во всех развитых платформах вызовы ожидания.