Блокировка файла. Множественный доступ к файлу
Автор: Тарасов А.Е. (ТАЕ)
Рецензент: Кузнецов В.А.
Дата: 01.2015
Скачать статью в формате Word
В языке Rexx не реализован функционал синхронизации записи в один файл разными процессами. Файл может быть много кратно открыт, как для чтения, так и для записи, но без всякого контроля. Для решения задачи необходимо написать самостоятельные процедуры, использующие в своей работе какой либо дополнительные признак.
В процессе изучения данного вопроса были намечены три признака, которые можно использовать для этих целей:
- Атрибуты файла.
- Семафоры, типа «взаимное исключение» (mutex).
- Использование файла флага.
Давайте отдельно остановимся на каждом из них:
* Атрибуты файла.
У каждого файла есть набор атрибутов: архив, каталог, скрытый, только чтение, системный. Так же существует возможность использовать расширенные атрибуты файлов. Мне понравилась идея использовать для маркировки файла его атрибуты в том, что сам файл начинает нести информацию о возможных режимах работы с ним, и не нужно привлекать дополнительные внешние средства.
От идеи использования расширенных атрибутов, пришлось отказаться сразу, так как они реализованы далеко не во всех файловых системах, и не все интерпретаторы Rexx имеют средства для работы с ними.
Из стандартных атрибутов файла, для работы было выбрано два: скрытый и системный.
В RexxUtil есть команда SysFileTree - получение информации о файлах (списках файлов). С её помощью можно не только искать файлы по маске атрибутов, но и устанавливать нужные атрибуты у всех найденных файлов.
Ложка дегтя оказалось в том, что в интерпретаторе Regina (который я использую в Windows) не реализована возможность установки атрибутов файлов. О чем прямо написано в документации. Иной возможности установить атрибуты файлов средствами Rexx найти не удалось. Что заставило воспользоваться для этих целей внешней утилитой, которая есть в любой ОС «attrib». Это решение значительно повысило временные расходы. Но лучше пока, ни чего нет.
В приведенных примерах в переменной «FileActual» содержится путь и имя файла, который необходимо блокировать.
/* Защита от одновременной записи в файл через атрибуты (одиночная блокировка) */
do until FileActual.0>0
call SysFileTree FileActual, 'FileActual','FN','**-*-'
if FileActual.0>0 then 'attrib +h "'FileActual'" > nul'
else call SysSleep Random(1,5)/10
end /* until FileSearch.0>0 */
/* Снятие защиты файла */
'attrib -h -s "'FileActual'" > nul'
/* Защита от одновременной записи в файл через атрибуты (двойная блокировка) */
do until FileActual.0>0
call SysFileTree FileActual, 'FileActual','FN','**-*-'
if FileActual.0>0 then do
'attrib +h "'FileActual'" > nul'
call SysSleep Random(2,10)/100 /* Пауза для раз синхронизации процессов 0,02-0,1 сек.*/
call SysFileTree FileActual, 'FileActual','FN','**+*-'
if FileActual.0>0 then 'attrib +s "'FileActual'" > nul'
end /* if */
else call SysSleep Random(1,5)/10 /* Пауза ожидания освобождения файла 0,1-0,5 сек.*/
end /* until FileSearch.0>0 */
/* Снятие защиты файла */
'attrib -h -s "'FileActual'" > nul'
* Семафоры, типа «взаимное исключение» (mutex).
Это заведуемые ОС структуры данных, координирующие доступ к устройствам посредством специального API. Семафоры используются как сигналы начала или окончания операций над ресурсом для обеспечения взаимоисключающего доступа к ним.
Как правило, семафоры используются для управления множественного доступа к ресурсу и совместного использование одного ресурса несколькими процессами. Семафоры определяется системой, и размещаются во внутренней памяти. Имена семафора должно включать префикс '/SEM32/'. Максимальная длина имени семафора в разных источниках указана разная. В инструкции к RexxUtil для OS/2 указана максимальная длина имени 255 символов, тогда как в «IBM Knowledge Center» (https://www-01.ibm.com/support/knowledgecenter/SSZND2_6.0.0/com.ibm.etools.iseries.orxw.doc/orxw_ref603.htm?lang=ru) для Object REXX указана максимальная длина 63 символа.
Rexx позволяет работать с двумя видами семафоров:
- «взаимное исключение» (mutex) - используется для систематизации доступа к ресурсам.
- «множественное ожидание» (muxwait) — ожидание наступления нескольких событий для доступа к ресурсам. Управление ожиданием наступления события происходит через «события семафора» (Event semaphores).
Семафоры управляются командами RexxUtil: SysCreate...() SysOpen...(), и SysClose...(). Дополнительно семафоры «взаимного исключения» (Mutex) управляются командами SysReleaseMutexSem() и SysRequestMutexSem(), а «события семафоров» управляются через команды: SysPostEventSem(), SysResetEventSem(), и SysWaitEventSem().
Для решения задачи множественного доступа к файлу воспользуемся семафором «взаимного исключения» (mutex).
В примерах переменная «SemName» содержит имя семафора.
/* Защита от одновременной записи в файл через семафоры*/
SemName='/SEM32/'Year||MonthDay
SemName=SysCreateMutexSem(SemName)
do while SysRequestMutexSem(SemName,10)<>0
end /* until */
/* Снятие защиты файла */
call SysReleaseMutexSem SemName
call SysCloseMutexSem SemName
* Использование файла флага.
Это классический вариант блокировки с использованием флагов в виде файлов. Система реализованная во многих программах. Главным недостатком является дополнительная нагрузка на диск и файловую систему. Достоинством, простота организации на любом языке программирования, что позволяет организовывать совместную работу разных программ от разных авторов.
При проработки этой темы рассматривалось два сценария работы:
- Создание файла блокировки при начале работе с исходным файлом, и последующее удаление флага. Ищем наличие флага.
- Изначальное создание файлов флагов для каждого файла, а при начале работы с исходным файлом перемещение (move) файла флага во временный каталог, с последующим возвратом. Ищем отсутствие файла.
Второй вариант, хоть и приводит к удвоению файлов, но должен позволять обойти ряд скольких мест. Не смотря на это, было принято решение все-таки реализовывать только первый вариант.
В приведенных примерах в переменной «FileActual» содержится путь и имя файла, который необходимо блокировать.
/* Защита от одновременной записи в файл через lock файл*/
do until FileActual.0=0
call SysFileTree FileActual'.lock', 'FileActual','FN','*****'
if FileActual.0=0 then call lineout FileActual'.lock'
else call SysSleep Random(1,5)/10
end /* until FileSearch.0=0 */
/* Снятие защиты файла */
call sysFileDelete FileActual'.lock'
Сравнительный анализ.
Теперь давайте сравним приведенные методы блокировки файлов между собой. Для чего проведем ряд тестовых запусков одного итого же скрипта, но с разными системами блокировка. Обрабатывать будем 209 файлов, общим объемом 6.7Мб.
Необходимо выбрать скрипт который агрессивно пытается забирать файла на монопольное использование. Для этих целей идеально подходит скрипт аналог команды “update”. Перед нашим скриптом поставим задачу проверить каждую строку в каждом файле на соответствие неким условиям, и если условия выполняются внести изменения в строку, после чего переписать файл. Условия подобраны так, что в каждом файле, будут найдены одна или несколько строк, для внесения изменений.
Для получения статистически данных, каждый вариант блокировки будет протестирован трижды.
В таблице приведены данные одиночного запуска скрипта, время в секундах.
№ |
Метод блокировки |
||
Атрибуты |
Семафоры |
Файлы |
|
1 |
68,985 |
31,196 |
23,335 |
2 |
57,135 |
23,258 |
22,997 |
3 |
58,355 |
22,495 |
23,031 |
Минимальные значения |
57,135 |
22,495 |
22,997 |
Средние значения |
61,492 |
25,650 |
23,121 |
Как видно из таблицы, минимальное время зафиксировано при использовании алгоритма на основе семафоров. За ним с минимальной разницей в 0,502 сек. идет метод на основе файловых флагов. А метод на основе использования атрибутов значительно проигрывает, что связано с вынужденным использованием внешней командой системы «attrib». Считаю, что если удастся найти замену команде «attrib», то результат будет как минимум на том же уровне.
Если смотреть на средние значения, то впереди метод на основе файловых флагов. На статистику метода семафоров отрицательно сказался результат первого замера, который аномально большой. Вероятно, на выполнение скрипта оказало влияние внешние факторы.
Опираясь на данные таблицы, можно сказать, что алгоритмы с использованием семафоров, и файловых флагов – показали примерно равные результаты.
Теперь давайте усложним задачу и при тех же условиях проверим, как поведут себя алгоритмы при одновременной работе четырех скриптов. У каждого из запущенных скриптов будут свои не пересекающиеся условия для проверки строк, но так что бы строки для изменения нашлись в каждом файле.
Данные по тестовым запускам сведем в следующую таблицу.
№ |
Атрибуты |
Значения |
||||
|
1 |
2 |
3 |
4 |
Минимальные |
|
1 |
72,867 |
81,024 |
79,432 |
66,356 |
66,356 |
74,920 |
2 |
79,848 |
80,852 |
81,323 |
81,323 |
79,848 |
80,837 |
3 |
72,999 |
71,396 |
73,203 |
71,390 |
71,390 |
72,247 |
Итого: |
66,356 |
76,001 |
||||
№ |
Семафоры |
Значения |
||||
1 |
2 |
3 |
4 |
Минимальные |
Средние |
|
1 |
37,689 |
38,055 |
36,859 |
35,822 |
35,822 |
37,106 |
2 |
38,211 |
38,957 |
39,270 |
37,918 |
37,918 |
38,589 |
3 |
37,965 |
38,814 |
37,962 |
36,691 |
36,691 |
37,858 |
Итого: |
35,822 |
37,851 |
||||
№ |
Файлы |
Значения |
||||
1 |
2 |
3 |
4 |
Минимальные |
Средние |
|
1 |
31,878 |
36,641 |
35,33 |
35,972 |
31,878 |
34,955 |
2 |
34,446 |
34,608 |
35,179 |
35,694 |
34,446 |
34,982 |
3 |
26,121 |
33,723 |
32,165 |
32,286 |
26,121 |
31,074 |
Итого: |
26,121 |
33,670 |
Как видно, результаты стали предсказуемо хуже, но не очень критично. Зато у нас появился практически безоговорочный лидер, это метод на основе файловых флагов. Хотя, если честно, я ожидал победу метода на основе семафоров, так как он позволяет минимизировать обращения к диску.
Выводы.
В данной статье мы рассмотрели три способы решения в Rexx задачи блокировки файлов при множественном доступе к нему. Эти методы, основанные на использовании:
- Атрибуты файла,
- Семафоры, типа «взаимное исключение» (mutex).
- Использование файла флага.
По результатам сравнительного анализа, самым быстрым оказался метод на основе файловых флагов. Значительно худшие показатели метода на основе атрибутов файлов, обусловлены использованием в работе внешней команды системы. Но сам метод интересен тем, что в нем сам файл несет всю информацию о режимах работы с ним. В определенный момент это может стать значимым отличием.
Окончательное решение, какой же метод использовать должен принимать программист, исходя из поставленной задачи и внешними факторами.