Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Локальные сети персональных компьютеров. Работа с сервером 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 определяет, надо ли блокировать запись сразу после ее добавления в группу:

0x00 Запись добавляется в группу, но не блокируется
0x01 Добавляемая запись блокируется для использования заблокировавшей его программой в монопольном режиме
0x03 Добавляемая запись блокируется для совместного использования

Параметр Timeout определяет период времени (в 18-x долях секунды), в течение которого файл-сервер будет ожидать, если запись нельзя заблокировать немедленно. Если для этого параметра задать нулевое значение, ожидание выполняться не будет.

Функция возвращает 0 при успешном завершении или код ошибки:

Код ошибки Значение
0x96 Мало памяти на файл-сервере
0xFE Истек период ожидания, заданный параметром Timeout, но запись так и не удалось заблокировать
0xFF Сбой при блокировании записи

Для удаления записи из группы можно использовать функцию ClearLogicalRecord():

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 прерывания INT 21h:

На входе: AH = D0h;
AL = Параметр LockDirective;
BP = Параметр Timeout;
DS:DX = Адрес имени логической записи.
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для удаления записи из списка вместо функции ClearLogicalRecord() можно использовать функцию D4h прерывания INT 21h:

На входе: AH = D4h;
DS:DX = Адрес имени логической записи.
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для удаления группы записей и разблокирования всех записей вместо функции ClearLogicalRecordSet() можно использовать функцию D5h прерывания INT 21h:

На входе: AH = D5h.
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для блокирования группы записей вместо функции LockLogicalRecordSet() можно использовать функцию D1h прерывания INT 21h:

На входе: AH = D1h;
AL = Регистр должен содержать значение 0;
BP = Параметр Timeout.
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для разблокирования записи вместо функции ReleaseLogicalRecord() можно использовать функцию D2h прерывания INT 21h:

На входе: AH = D2h;
DS:DX = Адрес имени логической записи;
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для разблокирования группы записей вместо функции ReleaseLogicalRecordSet() можно использовать функцию D3h прерывания INT 21h:

На входе: AH = D3h.
На выходе: Регистры не используются.

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();
}


[Назад] [Содеожание] [Дальше]