Почему опасно избавиться от энергозависимых?

В C++, volatile рассматривается тот же путь const : передача указателя на энергозависимые данные к функции, которая не хочет volatile модификатор инициировал ошибку компиляции.

int foo(int* bar) { /* snip */ }

int main()
{
    volatile int* baz;
    foo(baz); // error: invalid conversion from ‘volatile int*’ to ‘int*’
}

Почему это опасно? Это очевидно для const модификатор, который может повредить удаление его const правильность; но есть ли такая вещь как"volatile правильность"? Я не могу выяснить, как, передавая указатель на энергозависимые данные, поскольку указатель на энергонезависимые данные мог вызвать проблемы.

ОТРЕДАКТИРУЙТЕ Именно так Вас, парни знают, почему я использовал volatile во-первых: многие из Mac OS X OSAtomic семейство функций (для атомарных инкрементов, декрементов, дополнения, вычитания, сравнивают и подкачивают, и т.д.), берет volatile аргументы.

6
задан zneak 5 August 2010 в 03:54
поделиться

4 ответа

Компилятор может не только оптимизировать доступ к энергонезависимым переменным, он может обновлять их прогнозно / спекулятивно, пока это не влияет на последовательное выполнение программы.

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

Например, компилятор C ++ 03 совершенно законно преобразовывает

int result;
void sum_if_all_positive( std::array<N> ary )
{
    int sum = 0;
    result = -1;
    for( int i = 0; i < N; ++i ) {
        if (ary[i] < 0) return;
        sum += ary[i];
    }
    result = sum;
}

в

int result;
void sum_if_all_positive( std::array<N> ary )
{
    result = 0;
    for( int i = 0; i < N; ++i ) {
        if (ary[i] < 0) { result = -1; return; }
        result += ary[i];
    }
}

(хотя такое изменение обеспечит лучшую производительность, чем регистрация суммы, только на нескольких архитектурах с дешевым доступом к памяти и очень немногих На ум приходит архитектура Microchip PIC.)

5
ответ дан 8 December 2019 в 18:30
поделиться

Потому что модификатор volatile означает, что компилятор должен позаботиться о том, чтобы фактически выполнять каждое чтение / запись элемента изменчивых данных в точности так, как указано в стандарте C «абстрактная машина».

Когда модификатор volatile удаляется, доступ к данным может быть оптимизирован до тех пор, пока программа ведет себя «как если бы» доступ произошел до однопоточной точки зрения потока программы контроль обеспокоен. Другими словами, компилятор может обрабатывать энергонезависимую часть данных, как если бы компилятор и только компилятор могли видеть и изменять элемент данных (что имеет место в подавляющем большинстве случаев).

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

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

int foo(int* bar) { /* snip */ }

int main()
{
    volatile int* baz;

    int tmp = *baz;
    foo(&tmp);
    *baz = tmp;
}
9
ответ дан 8 December 2019 в 18:30
поделиться

Ну, в foo() компилятор больше не знает, что baz (или более строго bar) является непостоянным и поэтому может попытаться применить некоторые неуместные оптимизации.

0
ответ дан 8 December 2019 в 18:30
поделиться

Ключевое слово volatile означает, что значение должно загружаться и сохраняться из / в памяти каждый раз.

Рассмотрим код:

int foo(int* bar) { 
    while(*bar){ 
        //Do something...
    }
}

int main()
{
    volatile int num = 1;
    volatile int* baz = &num;
    //Start a seperate thread to change *baz evenutally... 
    foo(baz);
}

Когда компилятор видит цикл while и знает, что то, на что указывает bar, всегда будет 1. Почему он должен проверять каждый раз? Проверять каждый раз было бы крайне расточительно. volatile гарантирует, что компилятор выполняет эту проверку каждый раз, поэтому, когда другой поток изменяет значение, цикл while завершается.

0
ответ дан 8 December 2019 в 18:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: