Сначала позвольте мне упомянуть, что статическая глобальная переменная - это то же самое, что и глобальная переменная, за исключением того, что вы ограничиваете переменную областью действия файла. То есть Вы не можете использовать эту глобальную переменную в других файлах через ключевое слово extern
.
Таким образом, вы можете свести свой вопрос к глобальным переменным против изменчивых переменных.
Теперь на энергозависимости:
Как и const
, volatile
является модификатором типа.
Ключевое слово volatile
было создано, чтобы предотвратить оптимизацию компилятора, которая может сделать код некорректным, особенно при наличии асинхронных событий.
Объекты, объявленные как volatile
, не могут использоваться при определенных оптимизациях.
Система всегда считывает текущее истинное значение изменчивого объекта в том месте, где оно используется, даже если предыдущая инструкция запрашивала значение из того же объекта. Также значение объекта пишется сразу при назначении. Это означает, что нет кэширования энергозависимой переменной в регистр процессора.
Dr. У Jobb's есть отличная статья о летучих .
Вот пример из статьи доктора Джобба:
class Gadget
{
public:
void Wait()
{
while (!flag_)
{
Sleep(1000); // sleeps for 1000 milliseconds
}
}
void Wakeup()
{
flag_ = true;
}
...
private:
bool flag_;
};
Если компилятор видит, что Sleep()
является внешним вызовом, он будет предполагать, что Sleep()
не может изменить значение переменной flag_. Таким образом, компилятор может хранить значение flag_
в регистре. И в этом случае это никогда не изменится. Но если другой поток вызывает wakeup, первый поток все еще читает из регистра ЦП. Wait()
никогда не проснется.
Так почему бы просто не кэшировать переменные в регистры и полностью избежать проблемы?
Оказывается, что эта оптимизация действительно может сэкономить вам много времени в целом. Таким образом, C / C ++ позволяет вам явно отключить его с помощью ключевого слова volatile
.
Тот факт, что flag_
была переменной-членом, а не глобальной переменной (и не статической глобальной), не имеет значения. Объяснение после примера дает правильное обоснование, даже если вы имеете дело с глобальными переменными (и статическими глобальными переменными).
Распространенным заблуждением является то, что объявления переменной volatile
достаточно для обеспечения безопасности потока. Операции над переменной все еще не атомарны, даже если они не «кэшируются» в регистрах
volatile с указателями:
Volatile с указателями, работает как const с указателями.
Переменная типа volatile int *
означает, что переменная, на которую указывает указатель, является изменчивой.
Переменная типа int * volatile
означает, что сам указатель является энергозависимым.