Захват участков файлов
Семафоры удобны при синхронизации доступа к единому
ресурсу, такому как принтер или неделимая структура данных. Если же нам
нужна синхронизация доступа к ресурсу, имеющему внутреннюю структуру,
например к файлу с базой данных, лучше использовать другие методы.
Если говорить именно о файле, оказывается удобным блокировать доступ к
участкам файла. При этом целесообразно ввести два типа захватов: для чтения
и для записи. Захват для чтения разрешает
другим нитям читать из заблокированного участка и даже ставить туда такую
же блокировку, но запрещает писать в этот участок и, тем более, блокировать
его для записи. Этим достигается уверенность в том, что структуры данных,
считываемые из захваченного участка, никем не модифицируются, поэтому
гарантирована их целостность и непротиворечивость.
В свою очередь, захват для записи запрещает
всем, кроме установившей его нити, любой доступ к заблокированному участку
файла. Это означает, что данный участок файла сейчас будет модифицироваться,
и целостность данных в нем не гарантирована.
Блокировка участков файла в Unix
Захват участков файла в качестве средства синхронизации был известен еще
с 60-х годов, но в том виде, который описан в стандартах ANSI и POSIX,
он был реализован в ОС UNIX в начале 70-х.
В UNIX возможны два режима захвата: допустимая (advisory) и обязательная
(mandatory). Как та, так и другая блокировка может быть блокировкой чтения
либо записи. Допустимая блокировка является "блокировкой для честных":
она не оказывает влияния на подсистему ввода-вывода, поэтому программа,
не проверяющая блокировок или игнорирующая их, сможет писать или читать
из заблокированного участка без проблем. Обязательная блокировка требует
больших накладных расходов, но запрещает физический доступ к файлу: чтение
или запись, в зависимости от типа блокировки.
При работе с разделяемыми структурами данных в ОЗУ было бы удобно иметь
аналогичные средства, но их реализация ведет к большим накладным расходам,
даже на системах с виртуальной памятью, поэтому ни одна из известных автору
систем таких средств не имеет. Библиотека POSIX threads предоставляет
своеобразную форму мутекса, read/write lock, который, как и описанные
файловые примитивы, может быть многократно захвачен для чтения и лишь
однократно — для записи. Однако мы должны заводить такой примитив для
каждой единицы разделяемого ресурса и не можем одним вызовом захватить
сразу много подобных единиц.
Впрочем, в современных версиях системы UNIX есть возможность отображать
файл в виртуальную память. Используя при этом допустимую блокировку участков
файла, программы могут синхронизироовать доступ к нему (обязательная блокировка
делает невозможным отображение в память).
|