Читаем Linux API. Исчерпывающее руководство полностью

Вопрос «Насколько быстро можно установить и снять блокировку записи?» не имеет однозначного ответа, поскольку скорость этих операций зависит от структуры, используемой ядром для хранения таких блокировок, и от местоположения нашей блокировки внутри нее. Мы рассмотрим данную структуру чуть ниже, но сначала следует остановиться на требованиях, которые к ней предъявляются:

• ядро должно иметь возможность объединить новую блокировку с любыми существующими (удерживаемыми тем же процессом), если они имеют тот же режим и располагаются по любую сторону от нее;

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

• при создании новой блокировки посреди существующей, которая имеет другой режим, процедура разделения этой существующей блокировки (см. рис. 51.3) должна быть простой.

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

В данном списке также хранятся блокировки, созданные с помощью вызова flock(), и сведения об аренде открытого файла (мы коснемся темы аренды файлов в разделе 51.5, во время обсуждения файла /proc/locks). Однако блокировки таких типов обычно куда менее многочисленны и, следовательно, шансов повлиять на производительность у них тоже меньше, поэтому мы не станем останавливаться на них отдельно.

Рис. 51.6.Пример списка блокировок записей для одного файла

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

51.3.8. Семантика наследования и снятия блокировок

Семантика наследования и снятия блокировок, созданных с помощью вызова fcntl(), существенно отличается от аналогичной семантики для блокировок на основе flock(). Обратите внимание на следующие моменты.

• Блокировки записей не наследуются дочерним процессом после выполнения fork(). Для сравнения, в случае с вызовом flock() потомок наследует ссылки на блокировки своего родителя и может их снять; если это произойдет, родитель тоже потеряет данные блокировки.

• Блокировки записей сохраняются на протяжении выполнения вызова exec() (при этом стоит учитывать влияние флага FD_CLOEXEC, описанное ниже).

• Все потоки одного процесса разделяют один и тот же набор блокировок.

• Блокировки записей связаны как с процессом, так и с индексным дескриптором (см. раздел 5.4). Неудивительно, что при завершении процесса снимаются все его блокировки. Менее очевидное следствие такой связи — все блокировки, относящиеся к определенному файлу, снимаются, когда процесс закрывает соответствующий файловый дескриптор; при этом неважно, использовался ли он для получения блокировок. Например, в следующем коде вызов close(fd2) снимает блокировку, удерживаемую для файла testfile вызывающим процессом, хотя она была установлена через файловый дескриптор fd1:

struct flock fl;

fl.l_type = F_WRLCK;

fl.l_whence = SEEK_SET;

fl.l_start = 0;

fl.l_len = 0;

fd1 = open("testfile", O_RDWR);

fd2 = open("testfile", O_RDWR);

if (fcntl(fd1, cmd, &fl) == -1)

errExit("fcntl");

close(fd2);

Семантика, описанная в последнем пункте, действует независимо от способа получения тех или иных дескрипторов, ссылающихся на один и тот же файл, и от того, как они были закрыты. Например, для получения копии дескриптора открытого файла используются вызовы dup(), dup2() и fcntl(). А для его закрытия, помимо вызова close(), можно также применить операцию exec() с флагом FD_CLOEXEC или вызов dup2(), который закрывает дескриптор, указанный во втором аргументе, если тот является открытым.

Семантика наследования и снятия блокировок, установленных с помощью вызова fcntl(), — архитектурный изъян. Например, она делает проблематичным использование таких блокировок из библиотечных пакетов, так как функции библиотеки не могут исключить возможность того, что вызывающий процесс закроет дескриптор, который ссылается на заблокированный файл, и тем самым удалит установленную ими блокировку. В качестве альтернативы блокировку можно было бы связать с файловым, а не с индексным дескриптором. Но текущая семантика блокировки записей давно является устоявшейся и стандартизированной. К сожалению, это существенно ограничивает применение вызова fcntl().

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных