Блокирование логических записей
Для синхронизации процессов можно использовать не только физическое блокирование записей файлов, когда программа не сможет изменить их содержимое, как бы она ни старалась, но и так называемое блокирование логических записей. Логическая запись реально не существует в виде записи на диске, у нее есть только имя. Пользуясь этим именем, программа может блокировать и разблокировать логическую запись. Если запись уже была заблокирована одним процессом, второй процесс не сможет ее заблокировать до тех пор, пока первый процесс не разблокирует данную запись.
Средства сетевой оболочки позволяют создавать группы логических записей и блокировать их все вместе, по аналогии с группами блокируемых файлов и физических записей.
Логика использования логических записей проста. С каждой критичной частью, например базы данных, связывается группа имен, т. е. логических записей. Когда программа желает изменить содержимое этой критической части базы данных, она пытается заблокировать соответствующие логические записи. Если никакой другой процесс в сети не изменяет те же самые данные и уже не заблокировал данную группу логических записей, наша программа сможет заблокировать группу для себя.
Выполнив блокировку логических записей, программа выполняет все необходимые действия с файлами и затем разблокирует логические записи, предоставляя доступ к данным другим процессам.
Необходимо отметить, что при синхронизации процессов с помощью логических записей (а также семафоров, которые мы рассмотрим ниже) программы сами должны проверять состояние записей и правильно выполнять доступ к файлам, так как физически данные в файлах не блокируются.
Набор функций, используемый для работы с логическими записями, аналогичен набору функций для работы с физическими записями. Однако в отличие от физических записей, которые связаны с файлами и идентифицируются индексом файла, смещением и размером, логические записи идентифицируются по имени.
Для создания группы логических записей используется функция LogLogicalRecord().
Удалить запись из группы можно функцией ClearLogicalRecord(). Вся группа записей удаляется функцией ClearLogicalRecordSet().
Записи можно блокировать сразу при их добавлении в группу либо можно заблокировать сразу все записи, относящиеся к группе, вызвав функцию LockLogicalRecordSet().
Для разблокирования логической записи используется функция ReleaseLogicalRecord(). Если надо разблокировать сразу все логические записи, вызывайте функцию ReleaseLogicalRecordSet().
Функция LogLogicalRecord() имеет следующий прототип:
int LogLogicalRecord(char LogicalRecordName, BYTE LockDirective,WORD Timeout);
Параметр LogicalRecordName задает имя логической записи, добавляемой в группу блокируемых записей. Имя может иметь длину до 100 байт и должно быть в формате текстовой строки, закрытой двоичным нулем.
Параметр LockDirective определяет, надо ли блокировать запись сразу после ее добавления в группу:
0x00 | Запись добавляется в группу, но не блокируется |
0x01 | Добавляемая запись блокируется для использования заблокировавшей его программой в монопольном режиме |
0x03 | Добавляемая запись блокируется для совместного использования |
Функция возвращает 0 при успешном завершении или код ошибки:
Код ошибки | Значение |
0x96 | Мало памяти на файл-сервере |
0xFE | Истек период ожидания, заданный параметром Timeout, но запись так и не удалось заблокировать |
0xFF | Сбой при блокировании записи |
int ClearLogicalRecord(char LogicalRecordName);
Параметр этой функции задает имя логической записи, удаляемой из группы. Функция возвращает нулевое значение или значение 0xFF, если в группе нет указанной записи.
Функция ClearLogicalRecordSet() позволяет разблокировать все записи группы и удалить группу:
void ClearLogicalRecordSet(void);
Прототип функции LockLogicalRecordSet(), используемой для блокирования группы записей:
int LockLogicalRecordSet(WORD Timeout);
Параметр Timeout используется так же, как и при вызове функции LogLogicalRecord().
Функция возвращает 0 при успешном завершении или код ошибки:
Код ошибки | Значение |
0xFE | Истек период ожидания, заданный параметром Timeout, но запись так и не удалось заблокировать |
0xFF | Сбой при блокировании записи |
Для разблокирования отдельных записей используйте функцию ReleaseLogicalRecord():
int ReleaseLogicalRecord(char LogicalRecordName);
Параметр задает имя записи. Функция возвращает нулевое значение или значение 0xFF, если указанной записи нет в группе.
Если надо разблокировать сразу все записи, добавленные в группу, используйте функцию ReleaseLogicalRecordSet():
void ReleaseLogicalRecordSet(void);
Для добавления записей в группу вместо функции LogLogicalRecord() можно использовать функцию D0h прерывания INT21h:
На входе: | AH | = | D0h; |
AL | = | Параметр LockDirective; | |
BP | = | Параметр Timeout; | |
DS:DX | = | Адрес имени логической записи. | |
На выходе: | AL | = | Код ошибки или 0, если операция завершилась без ошибок. |
На входе: | AH | = | D4h; |
DS:DX | = | Адрес имени логической записи. | |
На выходе: | AL | = | Код ошибки или 0, если операция завершилась без ошибок. |
На входе: | AH | = | D5h. |
На выходе: | AL | = | Код ошибки или 0, если операция завершилась без ошибок. |
На входе: | AH | = | D1h; |
AL | = | Регистр должен содержать значение 0; | |
BP | = | Параметр Timeout. | |
На выходе: | AL | = | Код ошибки или 0, если операция завершилась без ошибок. |
Для разблокирования записи вместо функции ReleaseLogicalRecord() можно использовать функцию D2h прерывания INT 21h:
На входе: | AH | = | D2h; |
DS:DX | = | Адрес имени логической записи; | |
На выходе: | AL | = | Код ошибки или 0, если операция завершилась без ошибок. |
На входе: | AH | = | D3h. |
На выходе: | Регистры не используются. |