Засоби синхронізації в ядрі – ЧАСТИНА 1

попередньому розділі обговорювалися джерела і рішення проблем, повязаних з конкуренцією за ресурси На щастя, в ядрі Linux реалізована велика сімей-

ство засобів синхронізації У цій главі обговорюються ці кошти, інтерфейси до них, а також особливості їх роботи і використання Ці рішення дозволяють розробникам писати код, в якому відсутні стану конкуренції за ресурси

Атомарні операції

Атомарні операції (atomic operations) надають інструкції, які виконуються атомарне, – тобто не зупиняючись Так само як і атом спочатку вважався неподільною часткою, атомарні операції є неподільними інструкціями Наприклад, як було показано в попередньому розділі, операція атомарного инкремента дозволяє зчитувати з памяті і збільшувати на одиницю значення змінної за один неподільний і безперервний крок На відміну від стану конкуренції за ресурс, яка обговорювалася в попередній чолі, результат виконання такої операції завжди один і той же, наприклад, як показано в наступному прикладі (припустимо, що значення змінної i спочатку одно 7)

Потік 1 Потік 2

інкремент i (7 -> 8)

інкремент i (8 -> 9)

Результуюче значення 9 – правильне Паралельне виконання двох атомарних операцій з однією і тією ж змінної неможливо ніколи Таким чином, для такої операції інкремента стан конкуренції за ресурс виникнути не може

Ядро надає два набору інтерфейсів для виконання атомарних операцій: один – для роботи з цілими числами, а інший – для роботи з окремими бітами Ці інтерфейси реалізовані для всіх апаратних платформ, які підтримуються операційною системою Linux Більшість апаратних платформ підтримують атомарні операції або безпосередньо, або шляхом блокування

шини доступу до памяті при виконанні однієї операції (що в свою чергу гарантує, що інша операція не може виконатися паралельно) Це якось дозволяє впоратися з проблемою в разі апаратних платформ, таких як SPARC, які не підтримують базових машинних інструкцій для виконання атомарних операцій

Цілочисельні атомарні операції

Засоби виконання атомарних операцій з цілими числами працюють з типом даних atomict Замість того, щоб використовувати функції, які працюють безпосередньо з типом даних in t мови С, по ряду причин використовується спеціальний тип даних По-перше, функції, які виконують атомарні операції, приймають тільки аргументи типу atomict, це гарантує, що атомарні операції виконуються тільки з даними цього спеціального типу У той же час це також гарантує, що дані цього типу не зможуть передаватися в інші функції, які не виконують атомарних операцій Дійсно, нічого доброго не буде від таких атомарних операцій, які іноді атомарні, а іноді-ні Наступний момент-використання типу atomic_ t дозволяє гарантувати, що компілятор (помилково, але для підвищення ефективності) нічого очікувати оптимізувати операції звернення до атомарним змінним Важливо, щоб атомарні операції отримували правильне значення адреси змінної в памяті, а не адреси тимчасових копій І нарешті, за типом atomic t ховаються відмінності між реалізаціями для різних апаратних платформ

Крім того, що тип atomic_t – це 32-розрядне ціле число на всіх машинах, які підтримуються операційною системою Linux, при розробці коду необхідно враховувати, що максимальний діапазон значень змінної цього типу не може бути більше 24 біт Це повязано з апаратною платформою SPARC, для якої використовується трохи дивна реалізація атомарних операцій: в молодші 8 біт 32-розрядного цілого числа типу in t вбудована блокування, як показано па рис 91

32-розрядний тип atomic_ t

24-бітове знакове ціле Блокування

(Біт) 31 липня Про

Рис91, Структура 32-бітового типу atomic_t для апаратної платформи SPARC в старій реалізації

Блокування використовується для запобігання паралельного доступу до змінної атомарного типу, так як для апаратної платформи SPARC відсутня відповідна підтримка на рівні машинних інструкцій Отже, на машинах SPARC можуть бути використані тільки 24 біт Хоча код, який розрахований на використання пального 32-бітового діапазону значень, буде працювати і на машинах інших типів, він може приводити до дивних і підступним помилок на машинах типу SPARC, і так робити не потрібно Останнім часом розумні хакери додумалися, як для апаратної платформи SPARC забезпечити тип atomic_t, який позволя-

ет зберігати повноцінне 32-розрядне ціле число, і зазначеного обмеження більше не існує Проте стара 24-бітова реалізація все ще використовується в старому коді для апаратної платформи SPARC, і цей код все ще є у файлі

для цієї апаратної платформи

Оголошення все, що необхідно для використання цілочисельних атомарних операцій, знаходяться в заголовному файлі Для деяких апаратних платформ існують додаткові кошти, які унікальні тільки для цієї платформи, але для всіх апаратних платформ існує мінімальний набір операцій, які використовуються в ядрі всюди Пр і написанні коду ядра необхідно гарантувати, що відповідні операції доступні і правильно реалізовані для всіх апаратних платформ

Оголошення змінних типу atomic_ t проводиться звичайним чином При необхідності можна встановити задане значення цієї змінної

.  atomic_t u /* визначення змінної і * /

atomic_t v = ATOMIC_INIT (0) / * Визначення змінної v і ініціалізація її в значення нуль * /

Виконувати операції так само просто

atomic_set (& v, 4) / * V = 4 (атомарне) * / atomic_add (2, & v) / * V = v + 2 = 6 (атомарне) * / atomic_inc (& v) / * V = v + l = 7 (атомарне) * /

Якщо необхідно конвертувати тип atomic_ t в тип int, то потрібно використовувати функцію atomic_read ()

printk (% d \ n, atomic_read (& v)) / * Буде надруковано 7 * /

Наиболе е часте использовани е атомарний х цілочисельних х операци й – це інкремент лічильників Захищати один лічильник з допомогою складної системи блокувань – це нерозумно, тому розробники використовують виклики atomic_in t () і atomic_de c (), які значно швидше Ще одне використання атомарних цілочисельних операцій – це атомарну виконання операції з перевіркою результату Найбільш поширений приклад – це атомарні декремент і перевірка результату, за допомогою функції

int atomic_dec_and_test(atomic_t *v)

Ця функція зменшує на одиницю значення заданої змінної атомарного типу Якщо результат виконання операції дорівнює нулю, то повертається значення true, інакше повертається false Повний список всіх атомарних операцій з цілими числами (тобто тих, які доступні для всіх апаратних платформ) наведено в табл 91 Всі операції, які реалізовані для певної апаратної платформи, наведені у файлі

Зазвичай атомарні операції реалізовані як функції з підстановкою тіла і вбудованими інструкціями на мові асемблера (розробники ядра люблять inline) У разі якщо яка-небудь з функцій має внутрішньої атомарний, то зазвичай вона виконується у вигляді макросу Наприклад, для більшості нормальних апаратних платформ зчитування одного машинного слова даних – це атомарна операція Операція зчитування завжди повертає машинне слово в несуперечливою стані або перед операцією запису, або після неї, але під

час операції запису читання не може бути виконано ніколи . Отже, функція atomic_read () зазвичай реалізується як макрос, який повертає цілочисельне значення змінної типу atomic_t

Таблиця 91 Повний список всіх атомарних операцій з цілими числами

Атомарна целочисленная операція Опис

ATOMIC_INIT(int i)

in t atomic_ read(atomic_t *y)

void atomic_set (atomic_t  *v,    in t i)

void atomic_add (in t  i,  atomic_t  *v) void atomic_sub(int  i,  atomic_t  *v) void  atomic_inc(atomic_t *v)

void atomic_dec(atomic_t  *v)

int atomic_sub_and_test(int  i,  atomic_t  *v) int atomic_add_negative(int i,  atomic_t  *v) in t   atomic_dec_and_test  (atomic_t  *v) in t  atomic_inc_and_test(atomic_t *v)

Оголошення і ініціалізація в значення i змінної типу atomic_ t

Атомарну зчитування значення цілочисельний змінної v

Атомарне встановити змінну v в значення i атомарний додати значення i до змінної v атомарний відняти значення 1 із змінної v атомарний додати одиницю до змінної v атомарний відняти одиницю із змінної v атомарний відняти значення i з змінної v

і повернути true, якщо результат дорівнює нулю, і fals e інакше

Атомарне додати значення i до змінної v і повернути true, якщо результат операції менше нуля, інакше повернути fals e

Атомарне відняти одиницю із змінної v і повернути true, якщо результат операції дорівнює нулю, інакше повернути fals e

Атомарне додати одиницю до змінної v і повернути true, якщо результат операції дорівнює нулю, інакше повернути fals e

Атомарність і порядок виконання

Від атомарних операцій читання перейдемо до відмінностей між атомарний і порядком виконання Як вже розповідалося, операції читання одного машинного слова завжди виконуються атомарно Ці операції ніколи не перекриваються операціями запису того ж машинного слова Іншими словами, операція читання даних завжди повертає машинне слово в Консистентне стані: іноді повертається значення, яке було до запису, а іноді-то, яке стало після запису, але ніколи не повертається значення, яке було під час запису Наприклад, якщо цілочисельне значення спочатку було одно 42, а потім стало 365, то операція читання завжди поверне значення 42 або 365, але ніколи не змішане значення Це називаєтьсяатомарний

Джерело: Лав, Роберт Розробка ядра Linux, 2-е видання : Пер з англ – М: ТОВ «ІД Вільямс »2006 – 448 с : Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*