В чем разница между статической глобальной и статической изменчивой переменной?

StackOverflow https://stackoverflow.com/questions/346306

Вопрос

Я использовал статическую глобальную переменную и статическую изменчивую переменную в области файла,

оба обновляются с помощью ISR, а основной цикл и основной цикл проверяют значение переменной.

здесь при оптимизации не оптимизируется ни глобальная переменная, ни изменчивая переменная.Таким образом, вместо использования изменчивой переменной проблему решает глобальная переменная.

Так хорошо ли использовать глобальную переменную вместо изменчивой?

Есть ли какая-то конкретная причина использовать статическую изменчивость??

Любой пример программы будет полезен.

Заранее спасибо..

Это было полезно?

Решение

Это разные вещи. Я не эксперт по изменчивой семантике. Но я думаю, что имеет смысл то, что описано здесь.

Global

Глобальный просто означает, что рассматриваемый идентификатор объявлен в области видимости файла. Существуют различные области видимости: функция (где определены метки goto), & # 64257; файл (где находятся глобальные переменные), блок (где находятся нормальные локальные переменные) и прототип функции (где находятся параметры функции). Эта концепция просто существует, чтобы структурировать видимость идентификаторов. Это не имеет ничего общего с оптимизацией.

Static

static - это длительность хранения (мы не будем здесь это рассматривать) и способ присвоения имени, объявленного в пределах внутренней связи области файла. Это можно сделать для функций или объектов, которые требуются только в пределах одного блока перевода. Типичным примером может быть функция help, распечатывающая принятые параметры, которая вызывается только из функции main, определенной в том же файле .c.

6.2.2 / 2 в черновике C99:

  

Если объявление & # 64257; le scope   identi & # 64257; er для объекта или функции   содержит спецификацию класса хранения & # 64257; er   static, идентификатор & # 64257; er имеет внутренний   связь.

Внутренняя связь означает, что идентификатор не виден за пределами текущей единицы перевода (как функция volatile выше).

Летучие

Волатильность - это совсем другое: ( 6.7.3 / 6 )

  

Объект, имеющий volatile-quali & # 64257; ed   тип может быть модифицированным & # 64257;   реализация или есть другие   неизвестные побочные эффекты. Поэтому любой   выражение, относящееся к такому объекту   должны оцениваться в строгом соответствии   правилам абстрактной машины,   как описано в 5.1.2.3. Более того,   в каждой точке последовательности значение последнего   хранящийся в объекте должен согласовываться с   что предписано рефератом   машина, кроме как <>> # 64257;   упомянутые неизвестные факторы   ранее.

Стандарт предоставляет отличный пример для примера, где && будет избыточным ( 5.1.2.3/8 ):

  

Реализация может быть & # 64257;   взаимно-однозначное соответствие   абстрактная и актуальная семантика: в   каждая точка последовательности, значения   фактические объекты согласуются с   эти спецификации & # 64257;   семантика. Ключевое слово ||   будет избыточным.

Точки последовательности - это точки, где действие побочных эффектов, касающихся абстрактной машины , завершено (т.е. внешние условия, такие как значения ячеек памяти, не включены). Например, между ; и <=> между правым и левым, после <=> и возвратом из вызова функции находятся точки последовательности.

абстрактная семантика - это то, что компилятор может вывести из просмотра только последовательности кода в конкретной программе. Эффекты оптимизации здесь не имеют значения. фактическая семантика включает эффект побочных эффектов, возникающих при записи объектов (например, изменение ячеек памяти). Определение объекта как изменчивого означает, что каждый всегда получает значение объекта прямо из памяти (& Quot; как изменено неизвестными факторами & Quot;). Стандарт нигде не упоминает потоки, и если вы должны полагаться на порядок изменений или на атомарность операций, вы должны использовать зависящие от платформы способы, чтобы гарантировать это.

Для легкого понимания обзора у Intel есть отличная статья об этом здесь .

Что мне теперь делать?

Продолжайте объявлять ваши глобальные данные области файлов как изменчивые. Глобальные данные сами по себе не означают, что значение переменных будет равно значению, хранящемуся в памяти. И статика только делает ваши объектылокально по отношению к текущему модулю перевода (текущие <=> файлы и все остальные файлы, которые он включает в себя).

Другие советы

Сначала позвольте мне упомянуть, что статическая глобальная переменная - это то же самое, что и глобальная переменная, за исключением того, что вы ограничиваете переменную областью действия файла. То есть Вы не можете использовать эту глобальную переменную в других файлах через ключевое слово extern.

Таким образом, вы можете свести свой вопрос к глобальным переменным против изменчивых переменных.

Теперь на изменчивом:

Как и const, volatile - это модификатор типа.

Ключевое слово Sleep() было создано для предотвращения оптимизации компилятора, которая может привести к некорректности кода, особенно при наличии асинхронных событий.

Объекты, объявленные как flag_, нельзя использовать при определенных оптимизациях.

Система всегда считывает текущее истинное значение изменчивого объекта в той точке, в которой оно используется, даже если предыдущая инструкция запрашивала значение из того же объекта. Также значение объекта пишется сразу при назначении. Это означает, что нет кэширования энергозависимой переменной в регистр процессора.

доктор У Jobb's есть отличная статья о летучих .

Вот пример из статьи доктора Джобба:

class Gadget
{
public:
    void Wait()
    {
        while (!flag_)
        {
            Sleep(1000); // sleeps for 1000 milliseconds
        }
    }
    void Wakeup()
    {
        flag_ = true;
    }
    ...
private:
    bool flag_;
};

Если компилятор увидит, что Wait() является внешним вызовом, он предположит, что volatile int * не может изменить значение переменной flag_. Таким образом, компилятор может хранить значение int * volatile в регистре. И в этом случае это никогда не изменится. Но если другой поток вызывает wakeup, первый поток все еще читает из регистра ЦП. <=> никогда не проснется.

Так почему бы просто не кэшировать переменные в регистрах и полностью избежать проблемы? Оказывается, что эта оптимизация действительно может сэкономить вам много времени в целом. Таким образом, C / C ++ позволяет явно отключить его с помощью ключевого слова <=>.

Тот факт, что <=> был переменной-членом, а не глобальной переменной (и не статической глобальной), не имеет значения. Объяснение после примера дает правильное обоснование, даже если вы имеете дело с глобальными переменными (и статическими глобальными переменными).

Распространенным заблуждением является то, что объявления переменной <=> достаточно для обеспечения безопасности потока. Операции с переменной все еще не являются атомарными, даже если они не являются & Quot; cached & Quot; в регистрах

изменчиво с указателями:

Изменчиво с указателями, работает как const с указателями.

Переменная типа <=> означает, что переменная, на которую указывает указатель, является изменчивой.

Переменная типа <=> означает, что сам указатель является энергозависимым.

Ключевое слово «летучий» предлагает компилятору не выполнять определенные оптимизации кода, включающего эту переменную;если вы просто используете глобальную переменную, ничто не помешает компилятору ошибочно оптимизировать ваш код.

Пример:

#define MYPORT 0xDEADB33F

volatile char *portptr = (char*)MYPORT;
*portptr = 'A';
*portptr = 'B';

Без «летучести» первая запись может быть оптимизирована.

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

Изменчивая переменная в Википедии

В вашей текущей среде они могут не отличаться, но небольшие изменения могут повлиять на поведение.

  • Другое оборудование (больше процессоров, другая архитектура памяти)
  • Новая версия компилятора с лучшей оптимизацией.
  • Случайное изменение времени между потоками.Проблема может возникнуть только один раз из 10 миллионов.
  • Различные настройки оптимизации компилятора.

В долгосрочной перспективе гораздо безопаснее с самого начала использовать правильные многопоточные конструкции, даже если кажется, что пока все работает без них.

Конечно, если ваша программа не многопоточная, это не имеет значения.

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

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

Volatile в C не имеет ничего общего с аппаратным кэшем или многопоточностью. Он не вставляет ограждения памяти, и у вас нет абсолютно никаких гарантий порядка операций, если к нему обращаются два потока. Ключевое слово volatile в Java делает именно это: вставляет ограждения памяти, где это необходимо.

volatile переменная означает, что значение, переданное ей, не является константой, то есть если функция, содержащая volatile переменную " a = 10 " и функция добавляет 1 в каждом вызове этой функции, тогда она всегда будет возвращать обновленное значение. { volatile int a=10; a++; } Когда вышеупомянутая функция вызывается снова и снова, переменная a не будет повторно инициализирована до 10, она всегда будет показывать обновленное значение, пока программа не запустится. 1-й выход = 10 тогда 11 тогда 12 и так далее.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top