Они - разные вещи. Я не эксперт в энергозависимой семантике. Но я думаю, что это имеет смысл, что описано здесь.
Глобальный просто означает, что рассматриваемый идентификатор объявляется в объеме файла. Существуют различные объемы, вызванная функция (где goto-маркировки определяются в), п¬Ѓle (где globals находятся), блок (где нормальные локальные переменные находятся), и прототип функции (где параметры функции находятся). Это понятие просто существует для структурирования видимости идентификаторов. Это не имеет никакого отношения к оптимизации.
static
продолжительность хранения (мы не посмотрим на это здесь), и способ дать имя, объявленное в файле, определяют объем внутренней связи. Это может быть сделано для функций или возражает только требуемый в одной единице перевода. Типичный пример мог бы быть help
функция, распечатывающая принятые параметры, и который только называют от main
функция, определяемая в том же .c
файл.
6.2.2/2 в проекте C99:
, Если объявление п¬Ѓle определяет объем identiп¬Ѓer для объекта или функции, содержит класс памяти speciп¬Ѓer статичный, identiп¬Ѓer имеет внутреннюю связь.
Внутренняя связь означает, что идентификатор не видим вне текущей единицы перевода (как help
функция вышеупомянутых).
Энергозависимый другая вещь: ( 6.7.3/6)
объект, который имеет энергозависимый-qualiп¬Ѓed тип, может быть modiп¬Ѓed способами, неизвестными реализации, или иметь другие неизвестные побочные эффекты. Поэтому любое выражение, относящееся к такому объекту, должно быть оценено строго согласно правилам абстрактной машины, как описано в 5.1.2.3. Кроме того, в каждой последовательности указывают, что значение, в последний раз сохраненное в объекте, должно согласиться с предписанным абстрактной машиной, за исключением modiп¬Ѓed неизвестными факторами, упомянутыми ранее.
Стандарт предоставляет превосходный пример для примера, где volatile
было бы избыточно ( 5.1.2.3/8):
реализация могла бы deп¬Ѓne взаимно-однозначное соответствие между абстрактной и фактической семантикой: в каждой точке последовательности значения фактических объектов согласились бы с теми speciп¬Ѓed абстрактной семантикой. Ключевое слово
volatile
тогда было бы избыточно.
точки Последовательности являются точками, где эффект побочных эффектов относительно абстрактная машина завершается (т.е. внешние условия как значения элемента памяти не включены). Между правыми и левыми из &&
и ||
, после ;
и возвращающийся из вызова функции точки последовательности, например.
абстрактная семантика - то, что компилятор может вывести из наблюдения только последовательности кода в рамках конкретной программы. Эффекты оптимизации не важны здесь. фактическая семантика включают эффект побочных эффектов, сделанных путем записи в объекты (например, изменения элементов памяти). Квалификация объекта как энергозависимый означает, что тот всегда получает значение объекта прямо из памяти ("как изменено неизвестными факторами"). Стандарт не упоминает потоки нигде, и если необходимо полагаться на порядок изменений, или на атомарности операций, необходимо использовать зависимого платформы способы гарантировать это.
Для легкого для понимания обзора Intel имеет большую статью об этом здесь .
Продолжают объявлять Ваш объем файла (глобальные) данные как энергозависимый. Глобальные данные сам по себе не означают, что значение переменных будет равняться значению, сохраненному в памяти. И статичный действительно только делает Ваши объекты локальными для текущей единицы перевода (ток .c
файлы и все другие файлы #include'ed им).
Сначала позвольте мне упомянуть, что статическая глобальная переменная, совпадает с глобальной переменной, за исключением того, что Вы ограничиваете переменную объемом файла. Т.е. Вы не можете использовать эту глобальную переменную в других файлах через extern
ключевое слово.
, Таким образом, можно уменьшить вопрос глобальным переменным по сравнению с энергозависимыми переменными.
Теперь на энергозависимый:
Как const
, volatile
модификатор типа.
volatile
ключевое слово было создано для предотвращения оптимизации компилятора, которая может сделать код неправильным, конкретно когда существуют асинхронные события.
Объекты, объявленные как volatile
, не могут использоваться в определенной оптимизации.
система всегда читает текущее истинное значение энергозависимого объекта в точке, это используется, даже если предыдущая инструкция, которую попросили значения от того же объекта. Кроме того, значение объекта сразу записано на присвоении. Это означает, что нет никакого кэширования энергозависимой переменной в регистр ЦП.
у доктора Jobb есть большая статья об энергозависимом .
Вот пример от статьи доктора Jobb:
class Gadget
{
public:
void Wait()
{
while (!flag_)
{
Sleep(1000); // sleeps for 1000 milliseconds
}
}
void Wakeup()
{
flag_ = true;
}
...
private:
bool flag_;
};
, Если компилятор видит, что Sleep()
внешний вызов, он предположит, что Sleep()
не может возможно изменить переменное значение _ флага. Таким образом, компилятор может сохранить значение flag_
в регистре. И в этом случае, это никогда не будет изменяться. Но если другое пробуждение вызовов потока, первый поток все еще читает из регистра ЦП. Wait()
никогда не будет пробуждение.
Итак, почему не только никогда переменные кэша в регистры и не избегают проблемы полностью? Оказывается, что эта оптимизация может действительно сохранить Вас много времени в целом. Таким образом, C/C++ позволяет Вам явно отключать его через volatile
ключевое слово.
факт выше того flag_
был членской переменной, и не глобальной переменной (ни статичный глобальный) не имеет значения. Объяснение после примера дает корректное обоснование, даже если Вы имеете дело с глобальными переменными (и статическими глобальными переменными).
распространенное заблуждение А - то, что объявление переменной volatile
достаточно для обеспечения потокобезопасности. Операции на переменной все еще не являются атомарными, даже при том, что они не "кэшируются" в регистрах
энергозависимый с указателями:
Энергозависимый с указателями, работами как константа с указателями.
переменная А типа volatile int *
означает, что переменная, на которую указывает указатель, энергозависима.
переменная А типа int * volatile
означает, что сам указатель энергозависим.
"Энергозависимое" ключевое слово предлагает, чтобы компилятор не сделал определенную оптимизацию на коде, включающем ту переменную; если Вы просто используете глобальную переменную, ничто не предотвращает компилятор для неправильной оптимизации кода.
Пример:
#define MYPORT 0xDEADB33F
volatile char *portptr = (char*)MYPORT;
*portptr = 'A';
*portptr = 'B';
Без "энергозависимого", первая запись может быть оптимизирована.
Энергозависимое ключевое слово говорит компилятору удостоверяться, что переменная никогда не будет кэшироваться. Все доступы к нему должны быть сделаны последовательным способом для имения последовательного значения между всеми потоками. Если значение переменной должно быть изменено другим потоком, в то время как у Вас есть проверка цикла изменение, Вы хотите, чтобы переменная была энергозависима, поскольку нет никакой гарантии, что регулярное значение переменной не будет кэшироваться в какой-то момент, и цикл просто предположит, что это остается таким же.
Они не могут быть в различном в Вашей текущей среде, но тонкие изменения могли влиять на поведение.
намного более безопасно в конечном счете использовать надлежащие конструкции многопоточности с начала, даже если вещи, кажется, работают на данный момент без них.
, Конечно, если Ваша программа не является многопоточной тогда, она не имеет значения.
Я ответ +1 Фриоля. Я хотел бы добавить некоторую точность, поскольку, кажется, существует много беспорядков в различных ответах: энергозависимый C не является энергозависимым Java.
Поэтому сначала, компиляторы могут сделать, большая оптимизация на на основе потока данных Вашей программы, энергозависимой в C, предотвращает это, это удостоверяется Вы действительно загрузка и хранение к местоположению каждый раз (вместо того, чтобы использовать регистры вытирания его, например). Полезно, когда у Вас есть порт IO с отображенной памятью, как указал Фриоль.
Энергозависимый в C не имеет никакого отношения к аппаратным кэшам или многопоточности. Это не вставляет заборы памяти, и у Вас нет абсолютно никакого garanty на порядке операций, если два потока делают доступы к нему. Энергозависимое ключевое слово Java делает точно что хотя: вставка заборов памяти при необходимости.