Какой механизм блокировки ядра Linux лучше всего подходит для конкретного сценария?

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

Вопрос

Мне нужно решить проблему блокировки для этого сценария:

  1. Многопроцессорная система.
  2. Все процессоры используют общий (программный) ресурс.
  3. Доступ только для чтения к ресурсу очень распространен.(Обработка входящих сетевых пакетов)
  4. Доступ для записи встречается гораздо реже.(Изменяется практически только конфигурация).

В настоящее время я использую read_lock_bh, write_lock_bh (спинлоковый) механизм.Проблема в том, что чем больше процессоров, тем больше я получаю мягких зависаний в контексте записи.

Я прочитал главу о параллелизме в эта книга, Но не мог понять, получит ли читатель или писатель приоритет при использовании спиновых замков.

Итак, вопросы:

  1. Отдает ли механизм спин-блокировки Linux приоритет чтению/записи/ни одному из них?
  2. Есть ли лучший механизм, который я могу использовать, чтобы избежать этих мягких блокировок в моем сценарии, или, может быть, способ отдать приоритет писателю всякий раз, когда он пытается получить блокировку, используя мое текущее решение?

Спасибо, Нир

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

Решение

Вот прямая цитата из Основные драйверы устройств Linux это может быть то, что вы ищете.Кажется, часть, посвященная 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 появился еще один механизм под названием Обновление чтения-копирования (RCU), который дает повышение производительности, когда читатели намного превосходят писатели.Основная идея заключается в том, что потоки считывателей могут выполняться без блокировки.Потоки Writer более сложны.Они выполняют операции обновления на копии структуры данных и заменяют указатель, который видят читатели.Оригинальная копия сохраняется до тех пор, пока следующий контекст включит все процессоры, чтобы обеспечить завершение всех текущих операций чтения.Имейте в виду, что использование RCU является более вовлеченным, чем использование обсуждаемых примитивов до сих пор, и следует использовать только в том случае, если вы уверены, что это правильный инструмент для работы.Структуры данных RCU и функции интерфейса определены в include/linux/rcupdate.h.Существует обширная документация вDocumentation/RCU/*.

Пример использования RCU, посмотри на fs/dcache.c.На Linux каждый файл связан с информацией о записи каталогов (хранясь в структуре, называемой DENTRY), информацией о метаданных (хранящихся в INODE) ​​и фактическими данными (хранящиеся в блоках данных).Каждый раз, когда вы работаете в файле, компоненты в пути файла проанализированы, и получен соответствующие денри.Дентарины хранятся в кэшировании в структуре данных, называемой DCACHE, чтобы ускорить будущие операции.В любое время количество поисков DCACHE - это гораздо больше, чем обновления DCACHE, поэтому ссылки на DCACHE защищены с использованием примитивов RCU.

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

Разве не для таких случаев предназначен RCU?Видеть http://lwn.net/Articles/262464/ за хороший отзыв о его использовании.

Если работа, которую вы выполняете, удерживая блокировку, невелика, вы можете попробовать обычный мьютекс, а не чтение-запись.Это более эффективно.

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