НАЗВАНИЕ¶
select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO -
синхронное
мультиплексирование
ввода-вывода
КРАТКАЯ
СВОДКА¶
#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);
int pselect(int n, fd_set *readfds, fd_set
* writefds, fd_set *exceptfds, const struct
timespec * timeout, sigset_t * sigmask);
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);
ОПИСАНИЕ¶
Функции
select и
pselect ждут
изменения
статуса
нескольких
файловых
дескрипторов.
Они почти
идентичны,
только
- (i)
- select
использует
тайм-аут в
виде struct timeval (с
секундами и
микросекундами),
тогда как pselect
использует
struct timespec (с
секундами и
наносекундами).
- (ii)
- Функция
select может
обновить
параметр timeout,
чтобы
сообщить,
сколько
времени
осталось.
Функция pselect
не изменяет
этот
параметр.
- (iii)
- Функция
select не
содержит
параметра
sigmask, и ведет
себя как pselect с
параметром
sigmask, равным NULL.
Отслеживаются
три
независимых
набора
дескрипторов.
Те, что
перечислены
в параметре
readfds, будут
отслеживаться
на предмет
появления
новых
символов,
доступных
для чтения
(говоря
точнее,
операция
чтения не
будет
блокирована
-- в частности,
файловый
дескриптор
находится в
конце файла);
те, что
указаны в
параметре
writefds, будут
отслеживаться
на предмет
того, что
операция
записи не
будет
заблокирована;
те же, что
указаны в
параметре
exceptfds, будут
отслеживаться
на предмет
исключительных
ситуаций.
При возврате
из функции
наборы
дескрипторов
модифицируются,
чтобы
показать,
какие из них
изменили
свой статус.
Для
манипуляций
наборами
существуют
четыре
макроса:
FD_ZERO
очищает
набор.
FD_SET и
FD_CLR
добавляют
или удаляют
заданный
дескриптор
из набора.
FD_ISSET
проверяет,
является ли
дескриптор
частью
набора; этот
макрос
полезен
после
возврата из
функции
select.
n на единицу
больше
самого
большого
номера
дескриптора
из всех
наборов.
timeout -- это
верхняя
граница
времени,
которое
пройдет
перед
возвратом из
select. Можно
использовать
ноль, при
этом
select
завершится
немедленно.
(Это полезно
для
периодического
опроса.) Если
timeout равен NULL (нет
тайм-аута), то
select будет
ожидать
изменений
неопределенное
время.
sigmask -- это
указатель на
маску
сигналов (см.
sigprocmask(2)); если
этот
параметр не
равен NULL, то
pselect
сначала
замещает
текущую
маску
сигналов на
ту, на
которую
указывает
sigmask, затем
выполняет select,
и
восстанавливает
исходную
маску
сигналов.
Идея
pselect в том,
что если
нужно
подождать
события:
сигнала или
активности
на файловом
дескрипторе,
то требуется
атомарная
проверка,
чтобы
предотвратить
race condition.
(Предположим,
обработчик
сигнала
устанавливает
глобальный
флаг и
возвращает
управление.
Тогда
проверка
этого
глобального
флага, за
которой
следует
select(),
может
привести к
подвисанию,
если сигнал
появляется
сразу после
проверки, но
прямо перед
вызовом select. С
другой
стороны,
pselect
позволяет
сначала
заблокировать
сигналы,
обработать
пришедшие
сигналы, а
затем
вызвать
pselect() с
желаемой
sigmask,
тем самым
избегая race condition.)
Так как Linux в
настоящее
время не
содержит
системного
вызова
pselect(),
текущая
реализация
этой
процедуры в glibc
все еще
содержит race condition.
ВОЗВРАЩАЕМОЕ
ЗНАЧЕНИЕ¶
При успешном
завершении
select и
pselect
возвращают
количество
дескрипторов,
находящихся
в наборах
дескрипторов,
причем это
количество
может быть
равным нулю,
если
тайм-аут
истекает, а
интересующие
нас события
так и не
произошли.
При ошибке
возвращается
-1, а
errno
устанавливается
должным
образом;
наборы
дескрипторов
и значение
timeout
становятся
неопределены,
поэтому при
ошибке
нельзя
полагаться
на их
значение.
ОШИБКИ¶
- EBADF
- В одном из
наборов
находится
неверный
файловый
дескриптор.
- EINTR
- Был
пойман
незаблокированный
сигнал.
- EINVAL
- n
отрицательно.
- ENOMEM
- Функция
select не смогла
выделить
участок
памяти для
внутренних
таблиц.
ЗАМЕЧАНИЕ¶
В некоторых
программах
select
вызывается с
тремя
пустыми
наборами
файлов,
n
равным нулю,
и ненулевым
значением
timeout, что
является
довольно
переносимым
способом
сделать
задержку с
миллисекундной
точностью.
Под Linux
timeout
изменяется,
чтобы
сообщить
количество
времени,
которое не
было
использовано;
большинство
других
реализаций
не делают
этого. Это
приводит к
проблемам
как в коде
под Linux, который
читает
значение
timeout
и
переносится
в другие
операционные
системы, так
и когда код
переносится
под Linux и
использует
при этом struct timeval
для
нескольких
функций
select в
цикле без
повторной
инициализации.
Считайте,
что параметр
timeout
неопределен
после
возврата из
функции
select.
ПРИМЕР¶
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
/* Ждем, пока на стандартном вводе (fd 0) что-нибудь
появится. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Ждем не больше пяти секунд. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
/* Не полагаемся на значение tv! */
if (retval)
printf("Данные доступны.\n");
/* Теперь FD_ISSET(0, &rfds) вернет истинное значение. */
else
printf("Данные не появились в течение пяти секунд.\n");
exit(0);
}
СООТВЕТСТВИЕ
СТАНДАРТАМ¶
4.4BSD (функция
select
впервые
появилась в
4.2BSD). Обычно
переносится
с/на не-BSD
системы,
поддерживающие
уровень
BSD-сокетов
(включая
варианты System V).
Однако
заметьте,
что варианты
System V обычно
устанавливают
значение
переменной timeout
перед
выходом, а
вариант BSD --
нет.
Функция
pselect
определена в
IEEE Std 1003.1g-2000 (POSIX.1g). Ее
можно найти
в glibc2.1 и позднее.
Glibc2.0 содержит
функцию с
таким
именем, но
без
параметра
sigmask.
СМОТРИ
ТАКЖЕ¶
accept(2),
connect(2),
poll(2),
read(2),
recv(2),
send(2),
sigprocmask(2),
write(2)
ПЕРЕВОД¶
Copyright (C) Alexey Mahotkin <alexm@hsys.msk.ru> 2000-2001