Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСиСП теория 4 семестра - методичка слайдов Бранцевич Петр Юльянович 2009.doc
Скачиваний:
160
Добавлен:
15.06.2014
Размер:
1.75 Mб
Скачать

2.6 Мультиплексированный ввод/вывод

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

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

Системный вызов select позволяет получить информацию о состоянии файловых дескрипторов, используя тип fd_set, который определяет набор файловых дескрипторов. В системном вызове в качестве параметров указаны три параметра данного типа (а именно набор файловых дескрипторов, в которых ожидается момент доступности для чтения, readfds, или для записи, writefds, для сокетов – определяется исключительная ситуация, exceptfds). Первый параметр определяет значение файлового дескриптора, который на единицу больше, чем максимальное значение файлового дескриптора, состояние которого будет анализироваться. Последний параметр определяет время для анализа ситуации по файловым дескрипторам, если указатель NULL, то системный вызов сразу же возвратит значение, если же явно задано время в секундах и микросекундах, то на протяжении этого времени анализируется ситуация, после чего выдается значение. Структура, которая представляет время следующая:

struct timeval

{ long tv_sec;

long tv_usec; }

Имеются специальные макросы для работы с наборами файловых дескрипторов:

FD_CLR(int fd, fd_set *set);

FD_ISSET(int fd, fd_set *set);

FD_SET(int fd, fd_set *set);

FD_ZERO(fd_set *set);

Первый макрос устанавливает 0 в значение файлового дескриптора fd из заданного набора дескрипторов, второй – проверяет, включен ли файловый дескриптор в набор, третий – добавляет в набор файловый дескриптор, а четвертый – обнуляет набор файловых дескрипторов.

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

При ошибке возвращается -1 и переменная errno принимает одно из следующих значений:

EBADF – в одном из наборов содержится недопустимый дескриптор

EINTR – во время ожидания был получен сигнал

EINVAL – указанное значение тайм-аута недопустимо

ENOMEM – недостаточно памяти для выполнения запроса

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

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

#define TIMEOUT 2

#define BUF_LEN 1024

int main(void) {

struct timeval tv;

fd_set readfds;

int ret;

FD_ZERO(&readfds);

FD_SET(STDIN_FILENO, &readfds);

tv.tv_sec=TIMEOUT;

tv.tv_usec=0;

ret=select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv);

// проверяем можно ли читать с ввода/вывода

if (ret==-1)

{ perror(“select”);

return(1); }

else if (!ret)

{printf(“%d секунд прошли\n”, TIMEOUT;

return(0); }

if (FD_ISSET(STDIN_FILENO,&readfds))

// проверяем для ожидаемого файлового дескриптора

{ char buf[BUF_LEN+1];

int len;

len=read(STDIN_FILENO, buf, BUF_LEN);

if (len==-1)

{ perror(“read”);

return(1); }

if (len)

{ buf[len]=’\0’;

printf(“read: %s\n”, buf); }

return(0); }

else printf(“Такое невероятно !\n”);

return (1);

}

Принцип системного вызова select можно использовать для засыпания программы на время <1с. К примеру, select(0, NULL, NULL, NULL, &tv).

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

#include <sys/poll.h>

int poll(struct pollfd *fds, unsigned int nfds,int timeout);

Каждый элемент определяет такую структуру: первый элемент – номер дескриптора, второй – какие события должны наблюдаться для этого файла, третий же параметр – события, какие реально присущи файлу.

struct pollfd

{ int fd;

short events;

short revents; }

Поля events, revents определены битовыми масками:

POLLIN – есть данные для чтения

POLLRDNORM – есть обычные данные для чтения

POLLRDBAND – есть приоритетные данные для чтения

POLLPRI – есть срочные данные для чтения

POLLOUT – операция записи не заблокируется

POLLWRNORM – операция записи обычных данных не заблокируется

POLLWRBAND – запись приоритетных данных не заблокируется

POLLMSG –доступно сообщение SIGPOLL

В качестве возвращаемых событий:

POLLER – ошибка в указанном дескрипторах

POLLHUR – зависшее событие для данного дескриптора

POLLNVAL – дескриптор файла не допустим

Третий параметр определяет длину, ожидающую в миллисекундах (мс), когда интервал времени истекает, вызов возвращает значение, даже если дескриптор к вводу/выводу не обнаружены. Если этот параметр равен 0, то вызов возвращает значение немедленно.

Второй параметр – это сколько элементов массива наблюдается.

При успешном завершении системный вызов возвращается число дескрипторов, у которых revents не равно 0. Если их нет return(0) при ошибке – (-1). Ошибочные ситуации, значения которых заносятся в ERRNO:

EBADF – недопустимый дескриптор файла

EFAULT – указывается на fds, находящиеся за пределами адресного пространства

EINTR – получен сигнал до истечения времени

EINVAL – второй параметр больше чем значение

ENOMEN – нехватка памяти для выполнения запроса

Пример, который показывает работу системного вызова poll:

#include <sys/poll.h>

#include <stdio.h>

#include <unistd.h>

#define TIMEOUT 2

int main(void)

{

struct pollfd fds[2];

int ret;

fds[0].fd=STDIN_FILENO;

fds[0].events=POLLIN;

fds[1].fd=STDOUT_FILENO;

fds[1].events=POLLOUT;

// задание файловых дескрипторов и событий, которые ожидаются

ret=poll(fds, 2, TIMEOUT*1000);

// проверяются файловые дескрипторы, которые заданы

if (ret==-1)

{ perror(“poll”);

return(1); }

if (!ret)

{ printf(“%d секунд истекли\n”,TIMEOUT);

return(0); }

if (fds[0].revents & POLLIN)

{ printf(“stdin доступен на чтение \n”); }

if (fds[1].revents & POLLOUT)

{ printf(“stdout доступен для записи \n”); }

return(0);

}