Чтение онлайн

на главную - закладки

Жанры

Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform

Кёртен Роб

Шрифт:

Но на самом деле роль функции io_open гораздо значительнее. Она отвечает не только за проверку, может клиент открыть ресурс или нет, но также за следующее:

• инициализацию внутренних параметров библиотеки;

• привязку к запросу контекстного блока;

• привязку к контекстному блоку атрибутной записи.

Первые две операции выполняются с помощью функции базового уровня resmgr_open_bind, а привязка атрибутной записи сводится к простому присваиванию.

Будучи однажды вызвана, io_open выпадает из рассмотрения. Клиент может либо прислать сообщение ввода/вывода, либо нет, но в любом случае

должен будет однажды завершить «сеанс связи» с помощью сообщения, соответствующего функции close. Заметьте, что если клиента вдруг постигает внезапная смерть (например, он получает SIGSEGV, или выходит из строя узел, на котором он работает), операционная система автоматически синтезирует сообщение close, чтобы администратор ресурсов смог корректно завершить сессию. Поэтому вы гарантированно получите сообщение close!

Сообщения, которые должны быть сообщениями установления соединения, но таковыми не являются

Тут есть один интересный момент, который вы, может быть, для себя уже отметили. Прототип клиентской функции chown имеет вид:

int chown(const char *path, uid_t owner, gid_t group);

Вспомните: сообщение об установлении соединения всегда содержит имя пути и является либо однократным, либо устанавливает контекст для дальнейших сообщений ввода/ вывода.

Так почему же сообщение, соответствующее клиентской функции chown, не является сообщением установления соединения? К чему здесь сообщение ввода/вывода, когда в прототипе даже дескриптора файла нет?!

Ответ простой — чтобы облегчить вам жизнь.

Представьте себе, что было бы, если бы функции типа chown, chmod, stat и им подобные требовали от администратора ресурсов, чтобы он сначала анализировал имя пути, а затем уже выполнял нужные действия. (Именно так, кстати, все реализовано в QNX4.) Типичные проблемы этого подхода:

• Каждой функции приходится вызывать процедуру поиска.

• Для функций, у которых есть также версия, ориентированная на файловый дескриптор, драйвер должен обеспечить две отдельные точки входа: одну для версии с именем пути, и еще одну — версии с дескриптором файла.

В QNX/Neutrino же происходит следующее. Клиент создает составное сообщение — реально это одно сообщение, но оно включает в себя несколько сообщений администратору ресурсов. Без составных сообщений мы могли бы смоделировать функцию chown чем-то таким:

int chown(const char *path, uid_t owner, gid_t group) {

 int fd, sts;

 if ((fd = open(path, O_RDWR)) == -1) {

return (-1);

 }

 sts = fchown(fd, owner, group);

 close(fd);

 return (sts);

}

где функция fchown — это версия функции chown, ориентированная на файловые дескрипторы. Проблема здесь в том, что мы в этом случае используем три вызова функций (а значит, и три отдельных транзакции передачи сообщений) и привносим дополнительные накладные расходы применением функций open

и close на стороне клиента.

При использовании составных сообщений в QNX/Neutrino непосредственно клиентским вызовом chown создается одиночное сообщение, выглядящее примерно так:

Составное сообщение.

Сообщение состоит из двух частей. Первая часть посвящена установлению соединения (подобно сообщению, которое сгенерировала бы функция open), вторая — вводу/выводу (эквивалент сообщения, генерируемого функцией fchown). Никакого эквивалента функции close здесь нет, поскольку мы выбрали сообщение типа _IO_CONNECT_COMBINE_CLOSE, которое гласит: «Открой указанное имя пути, используй полученный дескриптор файла для обработки остальной части сообщения, а когда закончишь дела или столкнешься с ошибкой, закрой дескриптор».

Написанный вами администратор ресурса даже не заметит, вызвал ли клиент функцию chown или сначала сделал open, а потом вызвал fchown и далее close. Все это скрыто базовым уровнем библиотеки.

Составные сообщения

Как выясняется, концепция составных сообщений полезна не только для экономии ресурсов вследствие уменьшения числа сообщений (как в случае с chown, см. выше). Она также критически важна для обеспечения атомарности операций.

Предположим, что в клиентском процессе есть два или более потоков, работающих с одним дескриптором файла. Один из потоков в клиенте вызывает функцию lseek, за которой следует read. Все так, как мы и предполагаем. А вот если другой клиента попробует выполнить ту же самую последовательность операций с тем же самым дескриптором файла, вот тут у нас начнутся проблемы. Поскольку функции lseek и read друг о друге ничего не знают, то возможно, например, что первый поток выполнит lseek, а затем будет вытеснен вторым потоком. Второй поток выполнит свои lseek и read, после чего освободит процессор. Проблема здесь состоит в том, что поскольку эти два потока разделяют один и тот же дескриптор файла, у первого потока теперь получается неправильное смещение lseek, поскольку оно было изменено функциями lseek и read второго потока! Эта проблема проявляется также с дескрипторами файлов, которые дублируются (dup) между процессами, не говоря уже о сети.

Очевидным решением здесь является заключение lseek и read в пределы действия мутекса — когда первый поток захватит мутекс, мы будем знать, что он имеет эксклюзивный доступ к дескриптору. Второй поток должен будет ждать освобождения мутекса, прежде чем он сможет творить свое безобразие с позиционированием дескриптора.

К сожалению, если кто-то вдруг забудет захватить мутекс перед каждой и любой операцией с дескриптором файла, всегда остается возможность того, что такой «незащищенный» доступ может привести поток к чтению или записи данных не туда, куда надо.

Поделиться:
Популярные книги

Я снова не князь! Книга XVII

Дрейк Сириус
17. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я снова не князь! Книга XVII

На границе империй. Том 10. Часть 2

INDIGO
Вселенная EVE Online
Фантастика:
космическая фантастика
5.00
рейтинг книги
На границе империй. Том 10. Часть 2

Маяк надежды

Кас Маркус
5. Артефактор
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Маяк надежды

Законы Рода. Том 3

Flow Ascold
3. Граф Берестьев
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 3

Бастард Императора. Том 8

Орлов Андрей Юрьевич
8. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 8

Первый среди равных. Книга III

Бор Жорж
3. Первый среди Равных
Фантастика:
попаданцы
аниме
фэнтези
6.00
рейтинг книги
Первый среди равных. Книга III

Восход. Солнцев. Книга I

Скабер Артемий
1. Голос Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Восход. Солнцев. Книга I

На границе империй. Том 7. Часть 5

INDIGO
11. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 7. Часть 5

Real-Rpg. Еретик

Жгулёв Пётр Николаевич
2. Real-Rpg
Фантастика:
фэнтези
8.19
рейтинг книги
Real-Rpg. Еретик

Отмороженный 3.0

Гарцевич Евгений Александрович
3. Отмороженный
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Отмороженный 3.0

Газлайтер. Том 3

Володин Григорий
3. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 3

СД. Том 13

Клеванский Кирилл Сергеевич
13. Сердце дракона
Фантастика:
фэнтези
6.55
рейтинг книги
СД. Том 13

Хорошая девочка

Кистяева Марина
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Хорошая девочка

Вторая жизнь майора. Цикл

Сухинин Владимир Александрович
Вторая жизнь майора
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Вторая жизнь майора. Цикл