Главная страница Межпроцессное взаимодействие (состязание) вы STAT и FSTAT. Они различаются только тем, что первый из них требует имени файла, а второй полагается на дескриптор файла и полезен для открытых файлов, особенно для файлов стандартного ввода и вывода, имена которых не всегда известны. У обоих вызовов второй параметр указывает на структуру, куда нужно поместить информацию. Эта структура показана на листинге 1.2. Листинг 1.2. Структура, используемая для получения информации от системных вызовов STAT и FSTAT struct Stat { short st dev: /*устройство. которому принадлежит inode*/ unsigned short st ino: /*номер inode*/ unsigned short st mode; /*режим доступа*/ short st nlink: /*число ссылок на файл*/ short st u1d: /*идентификатор пользователя*/ short st gid: /*идентификатор группы*/ short st rdev: /*основное и вторичное */ /*устройство для специальных файлов*/ long st size: /*размер файла*/ long st atime: /*время последнего обращения*/ long st tntime: /*время последнего изменения*/ long st ctime; /*время последнего изменения inode*/ При работе с файловыми дескрипторами изредка может оказаться полезным системный вызов DUP. Например, рассмотрим программу, которая закрывает стандартный вывод (дескриптор 1), подставляет в качестве стандартного вывода другой файл, вызывает функцию, которая что-то пишет в этот файл, а затем восстанавливает исходное состояние. Если просто закрыть стандартный вывод и открыть новый файл, то новый файл станет стандартным выводом (если стандартный ввод, дескриптор которого равен О, используется), но восстановить состояние будет невозможно. Решение дает следующий оператор, который использует системный вызов DUP: fd = dup(l): При его выполнении в переменную fd помещается новый дескриптор, который будет соответствовать тому же файлу, что и стандартный вывод (1). Затем стандартный вывод можно закрыть, после чего открыть новый файл и использовать его. Когда понадобится восстановить исходное состояние, нужно закрыть файловый дескриптор 1 и выполнить код: п = dup(fd): В результате самый меньший из файловых дескрипторов, а именно 1, станет соответствовать тому же файлу, что и fd. Наконец, fd можно закрыть, в результате чего мы вернемся к той же ситуации, с которой начали. У системного вызова dup есть второй вариант, с помощью которого можно связать неиспользованный дескриптор с уже открытым файлом. Он записывается так: dup2(fd. fd2): Здесь fd это дескриптор открытого файла, а fd2 - не связанный ни с каким файлом дескриптор, который после выполнения вызова будет ссылаться на тот же файл. Таким образом, если fd ссылается на стандартный ввод (дескриптор равен 0), а дескриптор fd2 равен 4, то после выполнения вызова и О, и 4 будут соответствовать стандартному вводу. Для обеспечения взаимодействия между процессами в MINIX можно использовать каналы (pipes), как это уже было сказано выше. Когда пользователь дает оболочке команду cat filel file2 sort то оболочка создает канал и соединяет стандартный вывод первого процесса со входом канала, а стандартный ввод второго процесса с выходом. Чтобы создать канал, применяется системный вызов pipe, возвращающий два файловых дескриптора: один для чтения из канала и другой для записи в него. Обычно после этого делается вызов fork, и родительский процесс закрывает дескриптор для чтения, а дочерний процесс - дескриптор для записи (или наоборот), чтобы один процесс мог писать в канал, а другой - читать из него. В листинге 1.3 приведен скелет процедуры, создающей два процесса таким образом, что выход первого из них передается через канал во второй (более реалистичный пример делал бы проверку ошибок и обработку аргументов). Сначала создается поток, затем делается вызов fork, и родительский процесс становится первым процессом в канале, а дочерний процесс - вторым. Так как запускаемые файлы, processl и process2, ничего не знают о том, что они соединяются каналом, для работы программы необходимо, чтобы стандартный вывод первого процесса был соединен со стандартным вводом второго процесса каналом. Сначала родительский процесс закрывает дескриптор для чтения из канала. Затем он закрывает стандартный вывод и делает вызов dup, после которого стандартным выводом становится вход канала. Важно понимать, что dup всегда возвращает наименьший возможный дескриптор, в данном случае это будет 1. Наконец, исходный дескриптор для записи в канал закрывается. Листинг 1.3. Скелет процедуры, создающей конвейер из двух процессов #define STD INPUT О /* Дескриптор файла для стандартного устройства ввода */ idefine STD OUTPUT 1 /* Дескриптор файла для стандартного устройства вывода*/ pipeline(processl. process2) /* Указатели на имена программ */ char *processl. *process2: int fd[2]; pipe(&fd[0]): /* создать конвейер */ ifCforkO !=0) { /* Эти выражения исполняются родительским процессом */ close{fd[0]); /* Процесс 1 не нуждается в считывании из конвейера */ c1ose(STD 0UTPUT): /* Подготовка нового стандартного устройства вывода */ dup(fd[l]): /* Сделать стандартным устройством вывода fd[l] */ close(fd[l]); /* Этот дескриптор файла больше не нужен */ execl(processl.processl.0): } else { /* Эти выражения исполняются процессом-наследником */ close(fd[l]): /* Процесс 2 не нуждается в записи в конвейер */ close(STD INPUT): /* Подготовка нового стандартного устройства ввода */ dup(fd[0]): /* Сделать стандартным устройством ввода fd[0] */ close(fd[0]): /* Этот дескриптор файла больше не нужен */ execl(process2.process2.0): После вызова exec стартует процесс, у которого дескрипторы О и 2 остались без изменений, а дескриптор 1 соответствует записи в канал. Код дочернего процесса аналогичен. Значение параметра функции execl повторяется потому, что первым ее параметром должно быть имя программы, а вторым - значение первого аргумента запускаемой профаммы, которое для большинства программ должно совпадать с именем. Следующий системный вызов, ioctl, потенциально применим ко всем специальным файлам. Например, он используется драйверами блочных устройств, таких как SCSI драйвера для работы с ленточными накопителями и CD-ROM. Тем не менее он в основном применяется к символьным специальным файлам, особенно к терминалам. В стандарте POSIX определено несколько функций, которые транслируются библиотекой в вызовы ioctl. С помощью функций tcgetattr и tcsetattr можно изменить характеристики терминала, такие как коррекция ошибок, режим и т. д. Эти функции используют вызов ioctl. Режим с обработкой (cooked mode) - это нормальный режим работы терминала, в котором удаление символов работает нормально, символы Ctrl+S и Ctrl+Q соответственно останавливают и запускают вывод информации на терминал, Ctrl+D означает конец файла, а Del генерирует сигнал прерывания. Нажатие Ctrl+\ в этом режиме генерирует сигнал, по которому процесс принудительно прерывается, и выводится дамп памяти. В сьфол режиме (raw mode) вся эта дополнительная обработка отключается, и символы передаются программе напрямую. Более того, в этом режиме терминал не ждет окончания ввода строки, а передает символы программе сразу. Режим cbreak (cbreak mode) - промежуточный между двумя предыдущими. В этом режиме при редактировании не работают символы удаления и Ctrl+D, но Ctrl+S, Ctrl+Q, Del и Ctrl+\ работают. Как и в сыром режиме, символы передаются профаммам сразу, не дожидаясь окончания ввода строки (так как редактирование строк не работает, не обязательно дожидаться окончания ввода, потому что пользователь не сможет передумать и удалить введенные символы, как в режиме с обработкой). Термины cooked mode, raw mode и cbreak mode в стандарте POSIX не используются. Вместо этого POSIX определяет канонический режим (canonical mode), соответствующий режиму с обработкой. В нем определено одиннадцать специальных символов, и ввод ведется построчно. В неканоническом режиме (noncanonical mode) ввод данных определяется минимальным воспринимаемым количеством символов и временем (в десятых долях секунды). Стандарт POSIX очень гибок и определяет множество различных флагов, управляя которыми можно приблизить неканонический режим как к сырому* режиму, так и к режиму cbreak. Старые термины более содержательны, поэтому мы неформально будем придерживаться их. У вызова ioctl есть три параметра. Например, вызов функции toetattr преобразуется в следующий вызов: ioctl(fd. TCSETS. Stermios):
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |