[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]

Программирование: Разработка и отладка программ


Глава 7. Управление вводом и выводом

Данная глава содержит вводную информацию о программировании ввода-вывода и обзор функций управления вводом-выводом.

Функции библиотеки ввода-вывода предназначены для чтения данных из файлов (или получения от устройств) и записи данных в файл (или пересылки на устройство). Устройства рассматриваются системой как файлы ввода-вывода. Например, устройство необходимо открывать и закрывать точно так же, как и файл.

Некоторые функции используют для ввода-вывода данных стандартные файлы (устройства) ввода-вывода. Однако для большинства функций вы можете определять свои собственные файлы для ввода и вывода данных. Для многих функций можно использовать указатель на файл, т.е. на структуру, содержащую имя файла; для других вы можете использовать дескриптор файла (положительный целый идентификатор, присваиваемый файлу при его открытии).

Функции ввода-вывода, которые хранятся в библиотеке языка C (libc.a), осуществляют потоковый ввод-вывод. Для доступа к этим функциям необходимо включить в программу файл stdio.h следующим образом:

#include <stdio.h>

Некоторые функции библиотеки ввода-вывода - это макрокоманды, определенные в файле заголовка, а некоторые - это объектные модули функций. Во многих случаях библиотека содержит макрокоманду и функцию, которые выполняют одну и ту же операцию. Выбирая между макрокомандой и функцией, учтите следующее:

Файлы, команды и функции, применяемые для управления вводом-выводом, предоставляют следующие типы интерфейсов:

Низкоуровневый (Низкоуровневые интерфейсы ввода-вывода) Базовые функции открытия и закрытия файлов и устройств.
Потоковый (Потоковые интерфейсы ввода-вывода) Чтение-запись данных в режимах канала и FIFO.
Терминальный (Терминальные интерфейсы ввода-вывода) Форматированный вывод и буферизация.
Асинхронный (Асинхронные интерфейсы ввода-вывода) Одновременное выполнение операций обработки и ввода-вывода.
Языковой (Создание языка ввода с помощью команд lex и yacc) Для интерпретации данных ввода-вывода команды lex и yacc генерируют программы лексического и синтаксического анализа.

Низкоуровневые интерфейсы ввода-вывода

Низкоуровневый интерфейс ввода-вывода - это точка непосредственного входа в ядро. Она предоставляет такие функции, как открытие и закрытие файлов, чтение из файла и запись в файл.

Для чтения одной строки из стандартного ввода предназначена команда line. Другие операции низкоуровневого ввода-вывода выполняются следующими функциями:

open,openx или creat Подготовка файла или другого объекта каталога для чтения или записи путем присвоения ему дескриптора файла
read,readx, readv или readvx Чтение данных из открытого файла с указанным дескриптором
write, writex, writev и writevx Запись данных в открытый файл с указанным дескриптором
close Освобождение дескриптора файла

Функции open и creat помещают записи в три системные таблицы. В первую таблицу, выполняющую функции области данных (доступ к которой имеют функции чтения и записи) для процесса, записываются индексы дескрипторов файлов. Каждая запись в этой таблице содержит указатель на соответствующую запись во второй таблице.

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

В таблице файлов содержатся записи для всех экземпляров функции open или create в файле, а в таблицу i-узлов заносится только по одной записи для каждого файла.

Примечание: При обработке функций open или creat для конкретного файла система всегда вызывает функцию open для устройства, которая выполняет некоторые специальные операции (например, перематывает магнитную ленту или принимает сигнал DTR (сигнал готовности терминала) модема). Напротив, функция close используется системой только при закрытии файла последним процессом (т.е. при освобождении записи таблицы i-узлов файла). Это означает, что устройство может не зависеть от числа пользователей, за исключением случая, когда оно работает в монопольном режиме использования (в котором исключается его повторное открытие перед закрытием).

При выполнении операции чтения или записи для определения перечисленных ниже переменных используются аргументы, введенные пользователем, и информация, содержащаяся в записи таблицы файлов:

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

Если обрабатывается обычный файл, то номер логического блока должен быть преобразован в номер физического блока. Преобразовывать специальный блочный файл не нужно. Полученный номер физического блока используется для чтения данных с устройства или их записи.

Блочные драйверы устройств позволяют передавать информацию без использования буфера, непосредственно от пользовательского исполняемого модуля к устройству и обратно, причем размер буфера определяется в запросе вызывающей программы. Этот метод включает определение специального текстового файла, соответствующего устройству прямого доступа, и вызов функций чтения-записи для создания частного (не общего) заголовка буфера с соответствующей информацией. При желании могут вызываться отдельные функции открытия и закрытия, а также функция, выполняющая специальные действия с магнитной лентой.


Потоковые интерфейсы ввода-вывода

Потоковые интерфейсы, представляющие данные в виде потоков байтов, не интерпретируемых системой, более эффективны с точки зрения сетевых протоколов, чем символьные интерфейсы. При чтении-записи потока данных не происходит подразделения на отдельные записи. Например, при чтении 100 байтов по некоторому каналу невозможно определить, записал ли процесс сразу 100 байтов, или же он записал два раза по 50 байтов, или же эти 100 байтов поступили от двух разных процессов.

Потоковый ввод-вывод организован в виде каналов или файлов FIFO ("первым вошел - первым вышел"). Файлы FIFO схожи с каналами, поскольку данные в них могут двигаться только в одном направлении (слева направо). Однако, в отличие от канала, файлу FIFO можно присваивать имя и к нему могут обращаться не связанные с ним процессы. Иногда файл FIFO называют именованным каналом. Поскольку у файла FIFO есть имя, его можно открывать с помощью стандартной функции fopen. Процедура открытия канала сложнее: необходимо вызвать функцию pipe, возвращающую дескриптор файла, а затем с помощью стандартной функции ввода-вывода fdopen связать дескриптор открытого файла со стандартным потоком ввода-вывода.

Доступ к потоковым интерфейсам ввода-вывода можно получить с помощью следующих функций и макрокоманд:

fclose Закрывает поток
feof, ferror, clearerr и fileno Проверяет состояние потока
fflush Записывает все буферизованные на данный момент символы из потока
fopen, freopen или fdopen Открывает поток
fread и fwrite Выполняет двоичный ввод
fseek, rewind, ftell, fgetpos и fsetpos Перемещает указатель файла в потоке
getc, fgetc, getchar и getw Извлекает символ или слово из входного потока
gets и fgets Получает строку из потока
getwc,fgetwc или getwchar Извлекает "широкий" символ из входного потока
getws и fgetws Получает строку из потока
printf, fprintf, sprintf, wsprintf, vprintf, vfprintf, vsprintf и vwsprintf
  Печатает форматированный вывод
putc,putchar, fputc или putw Помещает символ или слово в поток
puts и fputs Записывает строку в проток
putwc, putwchar и fputwc Помещает символ или слово в поток
putws и fputws Помещает строку "широких" символов в поток
scanf, fscanf, sscanf или wsscanf Преобразует форматированный ввод
setbuf, setvbuf, setbuffer и setlinebuf Выделяет буфер для потока
ungetc и ungetwc Возвращает извлеченный символ обратно во входной поток

Терминальные интерфейсы ввода-вывода

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

Для каждого терминала или псевдотерминала существует структура tty, содержащая ИД текущей терминальной группы. Это поле определяет группу процессов, получающих сигналы, связанные с данным терминалом.

Доступ к терминальным интерфейсам ввода-вывода можно получить с помощью команды iostat, контролирующей загрузку системного устройства ввода-вывода, и демона uprintfd, позволяющего выводить сообщения ядра на экран терминала.

Демон открывает терминал, чтобы заносить сообщения об ошибках в файл протокола /dev/tty или /dev/console. Если фоновая запись запрещена, отключите процесс демона от управляющего терминала.

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

cfgetospeed,cfsetospeed, cfgetispeed или cfsetispeed
  Считывает и устанавливает значение скорости передачи в бодах
ioctl Выполняет управляющие функции, связанные с дескрипторами открытых файлов, такие как управление способностью фоновых процессов направлять вывод на управляющий терминал
termdef Запрашивает параметры терминала
tcdrain Ожидает завершения вывода
tcflow Выполняет функции управления потоком
tcflush Очищает указанную очередь
tcgetaattr Возвращает состояние терминала
tcgetpgrp Возвращает идентификатор интерактивной группы процессов
tcsendbreak Передает сигнал прерывания по асинхронной последовательной линии
tcsetattr Задает состояние терминала
ttylock,ttywait, ttyunlock или ttylocked
  Управляет функциями блокировки терминала
ttyname и isatty Считывает имя терминала
ttyslot Выполняет поиск участка в файле utmp для текущего пользователя

Асинхронные интерфейсы ввода-вывода

Функции асинхронного ввода-вывода позволяют процессу запускать операцию ввода-вывода и сразу после запуска операции или постановки в очередь выходить из функции. Если необходимо, чтобы процесс ожидал завершения операции ввода-вывода (или немедленно получал управление обратно, если операция уже завершена), то требуется другая функция. Таким образом, в режиме асинхронного ввода-вывода процесс может совмещать операции обработки и ввода-вывода или выполнять ввод-вывод на несколько устройств одновременно. Применение режима асинхронного ввода-вывода практически не влияет на быстродействие процесса, который считывает данные из файла на диске и записывает их в другой файл на диске, но значительно повышает производительность других типов программ ввода-вывода, например, программ копирования содержимого диска на магнитную ленту или создания изображения на графическом дисплее.

При асинхронном вводе-выводе можно (необязательно) установить режим, в котором ядро будет уведомлять процесс, выполняющий асинхронный ввод-вывод, о готовности определенного дескриптора к вводу-выводу (т.н. ввод-вывод по сигналу). Для уведомления пользовательского процесса ядро использует сигнал SIGIO.

Для работы в режиме асинхронного ввода-вывода процесс должен выполнить три действия:

  1. Установить обработчик сигнала SIGIO. Этот шаг необходим только в том случае, если установлен режим уведомления с помощью сигнала.
  2. Установить ИД процесса или ИД группы процессов, которые будут принимать сигналы SIGIO. Этот шаг необходим только в том случае, если установлен режим уведомления с помощью сигнала.
  3. Включить режим асинхронного ввода-вывода. Обычно решение о том, включать ли (загружать ли) этот режим, принимает системный администратор. Включение режима происходит при запуске системы.

Предусмотрены следующие функции асинхронного ввода-вывода:

aio_cancel Отменяет один или несколько ожидающих запросов асинхронного ввода-вывода
aio_error Получает информацию о состоянии ошибки запроса асинхронного ввода-вывода
aio_read Считывает информацию в асинхронном режиме из файла с указанным дескриптором
aio_return Определяет код возврата запроса асинхронного ввода-вывода
aio_suspend Переводит вызывающий процесс в состояние ожидания, пока не завершится один или несколько запросов асинхронного ввода-вывода
aio_write Записывает информацию в асинхронном режиме в файл с указанным дескриптором
lio_listio Инициализирует список запросов асинхронного ввода-вывода посредством одного вызова
poll и select Проверяет состояние ввода-вывода нескольких дескрипторов файлов и очередей сообщений

Для работы с функцией poll необходимо включить в программу следующие файлы заголовка:

poll.h Определяет структуры и флаги, используемые функцией poll
aio.h Определяет структуры и флаги, используемые функциями aio_read, aio_write и aio_suspend


[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]