Програмісти на C часто вважають мінливим, що означає, що змінна може бути змінена поза поточним потоком виконання; як результат, іноді вони спокушаються використовувати його в коді ядра, коли використовуються спільні структури даних. Іншими словами, вони, як відомо, розглядають летючі типи як якусь легку атомну змінну, якою вони не є. Використання летких у коді ядра майже ніколи не є правильним; у цьому документі описано, чому.
Ключовим моментом, що слід зрозуміти щодо енергонезалежності, є те, що його мета - придушити оптимізацію, яка майже ніколи не є тим, що дійсно хочеться робити. У ядрі потрібно захищати спільні структури даних від небажаного одночасного доступу, що дуже інше завдання. Процес захисту від небажаної одночасності також дозволить уникнути майже всіх проблем, пов'язаних з оптимізацією, більш ефективним способом.
Як і мінливі, примітиви ядра, які роблять одночасний доступ до даних безпечним (спинлок, мютекси, бар'єри пам'яті тощо), розроблені для запобігання небажаної оптимізації. Якщо вони правильно використовуються, не буде необхідності використовувати також летючі. Якщо непостійний все-таки необхідний, в коді десь є певна помилка. У правильно написаному коді ядра, летючі можуть служити лише для уповільнення речей.
Розглянемо типовий блок коду ядра:
spin_lock(&the_lock);
do_something_on(&shared_data);
do_something_else_with(&shared_data);
spin_unlock(&the_lock);
Якщо весь код дотримується правил блокування, значення shared_data не може несподівано змінитися під час утримування the_lock. Будь-який інший код, який може захотіти зіграти з цими даними, буде чекати на блокування. Спінлок-примітиви виступають як бар'єри пам'яті - вони прямо написані для цього - це означає, що доступ до даних не буде оптимізований через них. Таким чином, компілятор може подумати, що він знає, що буде у спільних_даних, але виклик spin_lock (), оскільки він виступає як бар'єр пам'яті, змусить його забути все, що він знає. Не буде проблем з оптимізацією доступу до цих даних.
Якби спільні_дані було оголошено мінливими, блокування все одно буде необхідним. Але компілятору також не вдасться оптимізувати доступ до shared_data в критичному розділі, коли ми знаємо, що ніхто з ним не може працювати. Поки блокування утримується, спільні_дані не змінюються. У роботі із спільними даними, правильне блокування робить непостійним непотрібним - та потенційно шкідливим.
Клас енергонезалежної пам'яті спочатку призначений для регістрів вводу / виводу, відображених на пам'ять. У межах ядра реєстрація доступу також повинна бути захищена блокуваннями, але також не хочеться, щоб компілятор "оптимізував" реєстрацію доступу в критичному розділі. Але всередині ядра доступ до пам'яті вводу / виводу завжди здійснюється через функції аксесуара; доступ до пам’яті вводу-виводу безпосередньо через покажчики нахмуриться і працює не у всіх архітектурах. Ці аксесуари написані для запобігання небажаної оптимізації, тому, знову ж таки, непостійні непотрібні.
Інша ситуація, коли можна спокусити використовувати летючі, - це коли процесор зайнятий-чекає значення змінної. Правильний спосіб зайняти очікування:
while (my_variable != what_i_want)
cpu_relax();
Виклик cpu_relax () може знижувати споживання енергії процесора або поступатися подвійному процесору з гіперпотоком; це також служить бар'єром пам’яті, тому, знову ж таки, мінливі зайві. Звичайно, очікування на зайнятість - це, як правило, антисоціальний акт, для початку.
Є ще кілька рідкісних ситуацій, коли непостійний має сенс у ядрі:
Вищезазначені функції аксесуарів можуть використовувати мінливі в архітектурах, де працює прямий доступ до пам'яті вводу / виводу. По суті, кожен виклик доступу стає самостійно критичним розділом і забезпечує доступ до нього так, як очікував програміст.
Вбудований код складання, який змінює пам'ять, але не має інших видимих побічних ефектів, ризикує видалити GCC. Додавання мінливого ключового слова до операторів ASM запобігає цьому видаленню.
Змінна jiffies особлива тим, що вона може мати різне значення кожного разу, коли вона посилається, але її можна читати без спеціального блокування. Таким чином, джиффи можуть бути мінливими, але додавання інших змінних цього типу сильно нахмуриться. У цьому плані Джиффі вважається проблемою "дурної спадщини" (слова Лінуса); виправити це було б більше проблем, ніж варто.
Покажчики на структури даних в когерентній пам'яті, які можуть бути змінені пристроями вводу / виводу, іноді можуть бути законно мінливими. Прикладом цього типу є буфер кільця, який використовується мережевим адаптером, де цей адаптер змінює покажчики, щоб вказати, які дескриптори були оброблені.
У більшості кодів не застосовується жодне з перерахованих вище виправдань для непостійних. Як результат, використання летючої речовини, ймовірно, буде розглядатися як помилка і внесе додатковий контроль до коду. Розробники, які спокушаються використовувати леткі, повинні зробити крок назад і подумати над тим, що вони справді намагаються досягти.