Локальные сети персональных компьютеров. Работа с сервером Novell NetWare© Александр Фролов, Григорий ФроловТом 9, М.: Диалог-МИФИ, 1993, 168 стр. 5.3. Блокирование логических записейДля синхронизации процессов можно использовать не только физическое блокирование записей файлов, когда программа не сможет изменить их содержимое, как бы она ни старалась, но и так называемое блокирование логических записей. Логическая запись реально не существует в виде записи на диске, у нее есть только имя. Пользуясь этим именем, программа может блокировать и разблокировать логическую запись. Если запись уже была заблокирована одним процессом, второй процесс не сможет ее заблокировать до тех пор, пока первый процесс не разблокирует данную запись. Средства сетевой оболочки позволяют создавать группы логических записей и блокировать их все вместе, по аналогии с группами блокируемых файлов и физических записей. Логика использования логических записей проста. С каждой критичной частью, например базы данных, связывается группа имен, т. е. логических записей. Когда программа желает изменить содержимое этой критической части базы данных, она пытается заблокировать соответствующие логические записи. Если никакой другой процесс в сети не изменяет те же самые данные и уже не заблокировал данную группу логических записей, наша программа сможет заблокировать группу для себя. Выполнив блокировку логических записей, программа выполняет все необходимые действия с файлами и затем разблокирует логические записи, предоставляя доступ к данным другим процессам. Необходимо отметить, что при синхронизации процессов с помощью логических записей (а также семафоров, которые мы рассмотрим ниже) программы сами должны проверять состояние записей и правильно выполнять доступ к файлам, так как физически данные в файлах не блокируются. Набор функций, используемый для работы с логическими записями, аналогичен набору функций для работы с физическими записями. Однако в отличие от физических записей, которые связаны с файлами и идентифицируются индексом файла, смещением и размером, логические записи идентифицируются по имени. Для создания группы логических записей используется функция LogLogicalRecord(). Удалить запись из группы можно функцией ClearLogicalRecord(). Вся группа записей удаляется функцией ClearLogicalRecordSet(). Записи можно блокировать сразу при их добавлении в группу либо можно заблокировать сразу все записи, относящиеся к группе, вызвав функцию LockLogicalRecordSet(). Для разблокирования логической записи используется функция ReleaseLogicalRecord(). Если надо разблокировать сразу все логические записи, вызывайте функцию ReleaseLogicalRecordSet(). Функция LogLogicalRecord() имеет следующий прототип: int LogLogicalRecord(char LogicalRecordName, BYTE LockDirective,WORD Timeout); Параметр LogicalRecordName задает имя логической записи, добавляемой в группу блокируемых записей. Имя может иметь длину до 100 байт и должно быть в формате текстовой строки, закрытой двоичным нулем. Параметр LockDirective определяет, надо ли блокировать запись сразу после ее добавления в группу:
Параметр Timeout определяет период времени (в 18-x долях секунды), в течение которого файл-сервер будет ожидать, если запись нельзя заблокировать немедленно. Если для этого параметра задать нулевое значение, ожидание выполняться не будет. Функция возвращает 0 при успешном завершении или код ошибки:
Для удаления записи из группы можно использовать функцию ClearLogicalRecord(): int ClearLogicalRecord(char LogicalRecordName); Параметр этой функции задает имя логической записи, удаляемой из группы. Функция возвращает нулевое значение или значение 0xFF, если в группе нет указанной записи. Функция ClearLogicalRecordSet() позволяет разблокировать все записи группы и удалить группу: void ClearLogicalRecordSet(void); Прототип функции LockLogicalRecordSet(), используемой для блокирования группы записей: int LockLogicalRecordSet(WORD Timeout); Параметр Timeout используется так же, как и при вызове функции LogLogicalRecord(). Функция возвращает 0 при успешном завершении или код ошибки:
После того как группа записей заблокирована, вы можете разблокировать отдельные записи или всю группу сразу. Для разблокирования отдельных записей используйте функцию ReleaseLogicalRecord(): int ReleaseLogicalRecord(char LogicalRecordName); Параметр задает имя записи. Функция возвращает нулевое значение или значение 0xFF, если указанной записи нет в группе. Если надо разблокировать сразу все записи, добавленные в группу, используйте функцию ReleaseLogicalRecordSet(): void ReleaseLogicalRecordSet(void); Для добавления записей в группу вместо функции LogLogicalRecord() можно использовать функцию D0h прерывания INT 21h:
Для удаления записи из списка вместо функции ClearLogicalRecord() можно использовать функцию D4h прерывания INT 21h:
Для удаления группы записей и разблокирования всех записей вместо функции ClearLogicalRecordSet() можно использовать функцию D5h прерывания INT 21h:
Для блокирования группы записей вместо функции LockLogicalRecordSet() можно использовать функцию D1h прерывания INT 21h:
Для разблокирования записи вместо функции ReleaseLogicalRecord() можно использовать функцию D2h прерывания INT 21h:
Для разблокирования группы записей вместо функции ReleaseLogicalRecordSet() можно использовать функцию D3h прерывания INT 21h:
5.3.1. Программа LOGLOCKПрограмма LOGLOCK (листинг 24) демонстрирует использование логических записей для синхронизации процессов. Вначале программа запрашивает в цикле у оператора имена логических записей и добавляет их в набор. Цикл добавления записей завершается, когда оператор вводит символ "-". Затем программа выполняет попытку заблокировать группу записей. Вы можете запустить эту программу одновременно на двух рабочих станциях. При попытке заблокировать уже заблокированную ранее логическую запись программа перейдет в состояние ожидания. Перед завершением своей работы программа LOGLOCK разблокирует записи и удалит набор. // =================================================== // Листинг 24. Блокирование логических записей // Файл loglock\loglock.cpp // // (C) A. Frolov, 1993 // =================================================== #include <stdlib.h> #include <stdio.h> #include <string.h> #include <conio.h> #define BYTE unsigned char #define WORD unsigned int extern "C" int GetNetWareShellVersion(char *,char *, char *); extern "C" int LogLogicalRecord(char *, BYTE, WORD); extern "C" int LockLogicalRecordSet(WORD); extern "C" void ReleaseLogicalRecordSet(void); extern "C" void ClearLogicalRecordSet(void); void main(void) { char MajorVersion=0; char MinorVersion=0; char Revision=0; char LogicalRecordName[100]; int ccode; printf("\n*LOGLOCK* (C) Frolov A., 1993\n"); // Проверяем наличие сетевой оболочки asm push si GetNetWareShellVersion(&MajorVersion, &MinorVersion, &Revision); asm pop si if(MajorVersion == 0) { printf("\nОболочка NetWare не загружена\n"); return; } // Создаем набор логических записей, которые будут заблокированы for(;;) { printf("\nВведите имя логической записи или '-':"); gets(LogicalRecordName); if(LogicalRecordName[0] == '-') break; // Добавляем логическую запись в набор ccode = LogLogicalRecord(LogicalRecordName, 0, 0); if(!ccode) printf("Логическая запись %s добавлена к списку\n", LogicalRecordName); else printf("Ошибка при добавлении %02.2X\n", ccode); } // Блокируем набор логических записей ccode = LockLogicalRecordSet(0); if(!ccode) printf("Логические записи заблокированы\n"); else printf("Ошибка при блокировании " "логических записей %02.2X\n", ccode); printf("Для разблокирования логических записей " " нажмите любую клавишу\n"); getch(); // Разблокируем набор логических записей ReleaseLogicalRecordSet(); // Удаляем набор логических записей ClearLogicalRecordSet(); } |