Вот прямая цитата из Essential Linux Device Drivers , которая может быть тем, что вы ищете. Похоже, что часть, которая имеет дело с RCU в конце, может вас заинтересовать.
Блокировка чтения-записи
Другим специализированным механизмом регулирования параллелизма является вариант спин-блокировки для чтения и записи. Если использование
критический раздел таков, что отдельные потоки либо читают, либо записывают в общую структуру данных, но не делают
оба, эти замки являются естественной посадкой. Несколько критических потоков разрешены внутри критической области одновременно.
Спинлоки блокировки считывателя определяются следующим образом:
rwlock_t myrwlock = RW_LOCK_UNLOCKED;
read_lock(&myrwlock); /* Acquire reader lock */
/* ... Critical Region ... */
read_unlock(&myrwlock); /* Release lock */
Однако, если поток писателя входит в критическую секцию, другие потоки читателя или писателя не допускаются внутрь. Использовать
писатель спинлоков, вы бы написали так:
rwlock_t myrwlock = RW_LOCK_UNLOCKED;
write_lock(&myrwlock); /* Acquire writer lock */
/* ... Critical Region ... */
write_unlock(&myrwlock); /* Release lock */
Посмотрите на код маршрутизации IPX, представленный в net/ipx/ipx_route.c
, для реального примера спинлока блокировки чтения-записи.
Блокировка чтения-записи с именем ipx_routes_lock
защищает таблицу маршрутизации IPX от одновременного доступа. Потоки
что нужно искать в таблице маршрутизации для пересылки блокировок чтения запросов на пакеты. Темы, которые нужно добавить или
удалить записи из таблицы маршрутизации, получить блокировку записи. Это улучшает производительность, потому что обычно есть
гораздо больше случаев поиска таблиц маршрутизации, чем обновлений таблиц маршрутизации.
Как и обычные спин-блокировки, блокировки чтения-записи также имеют соответствующие варианты irq, а именно read_lock_irqsave()
,
read_lock_irqrestore()
, write_lock_irqsave()
и write_lock_irqrestore()
. Семантика этих
функции аналогичны функциям обычных спин-блокировки.
Блокировки последовательностей или seqlocks, представленные в ядре 2.6, являются блокировками чтения-записи, когда записи предпочтительнее
читатели. Это полезно, если операции записи в переменную намного превосходят число обращений к чтению. Примером является
jiffies_64
переменная, обсужденная ранее в этой главе. Писатель темы не ждет читателей, которые могут быть внутри
критический раздел. Из-за этого потоки читателей могут обнаружить, что их запись в критическом разделе не удалась
и, возможно, потребуется повторить попытку:
u64 get_jiffies_64(void) /* Defined in kernel/time.c */
{
unsigned long seq;
u64 ret;
do {
seq = read_seqbegin(&xtime_lock);
ret = jiffies_64;
} while (read_seqretry(&xtime_lock, seq));
return ret;
}
Писатели защищают критические области, используя write_seqlock()
и write_sequnlock()
.
Ядро 2.6 представило еще один механизм, называемый Read-Copy Update (RCU) , , который улучшил производительность
производительность, когда читателей намного больше, чем авторов . Основная идея состоит в том, что потоки читателя могут выполняться без
замок. Писатель темы более сложный. Они выполняют операции обновления над копией структуры данных и
замените указатель, который видят читатели. Оригинальная копия сохраняется до следующего переключения контекста на всех процессорах в
обеспечить завершение всех текущих операций чтения. Имейте в виду, что использование RCU является более сложным, чем использование
Примитивы обсуждались до сих пор и должны использоваться, только если вы уверены, что это правильный инструмент для работы. Данные RCU
структуры и функции интерфейса определены в include/linux/rcupdate.h
. В документации достаточно
Documentation/RCU/*
.
Пример использования RCU приведен в fs/dcache.c
. В Linux каждый файл связан с записью каталога
информация (хранящаяся в структуре, называемой dentry), информация метаданных (хранящаяся в inode) и фактические данные
(хранится в блоках данных). Каждый раз, когда вы работаете с файлом, компоненты в пути к файлу анализируются, и
соответствующие зубные камни получены. Дентрии хранятся в кэше в структуре данных, называемой dcache, для
ускорить будущие операции. В любое время количество поисков dcache намного больше, чем обновлений dcache, поэтому
ссылки на dcache защищены с помощью примитивов RCU.