select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - многопоточный синхронный ввод-вывод
НАЗВАНИЕselect, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO -
многопоточный синхронный ввод-вывод
СИНТАКСИС
/* В соответствие с POSIX 1003.1-2001 */
#include
/* В соответствие с более ранними стандартами */
#include
#include
#include
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, const
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 ждут изменения статуса нескольких
файловых описателей.
Эти функции идентичны, за исключением 3-х отличий между
ними:
(1) Функция select использует время ожидания, которое
задано в структуре struct timeval (с секундами и
микросекундами), тогда как pselect использует
struct timespec (с секундами и наносекундами).
(2) Функция select может обновить параметр timeout,
который показывает сколько времени прошло. Функция
pselect не изменяет этот параметр.
(3) Функция select не имеет параметра sigmask, и т.о.
ведет себя также как функция pselect вызванная с
этим параметром, установленным в NULL.
Отслеживаются 3 независимых набора описателей. Те, что
перечислены в readfds, будут отслеживаться для того, чтобы
обнаружить появление символов, доступных для чтения
(говоря более точно, чтобы узнать, не будет ли блокировано
чтение; описатель файла также будет указывать на конец
файла); те описатели, которые указаны в writefds, будут
отслеживаться для того, чтобы узнать, не заблокирован ли
процесс записи; те же, что указаны в параметре exceptfds,
будут отслеживаться для обнаружения исключительных
ситуаций. При возврате из функции наборы описателей
модифицируются, чтобы показать, какие описатели фактически
изменили свой статус.
Для манипуляций наборами существуют четыре макроса:
FD_ZERO, очищающий набор; FD_SET и FD_CLR добавляют
заданный описатель к набору или удаляют его из набора;
FD_ISSET проверяет, является ли описатель частью набора;
этот макрос полезен после возврата из функции select.
n на единицу больше самого большого номера описателей из
всех наборов.
timeout - это верхняя граница времени, которое пройдет
перед возвратом из select. Можно использовать нулевое
значение, и при этом select завершится немедленно. Если
timeout равен NULL (нет времени ожидания), то select будет
ожидать изменений неопределенное время.
sigmask - это указатель на маску сигнала (см. sigproc-
mask(2)); если он не равняется NULL, то pselect сначала
заменяет текущую маску сигнала на ту, на которую указывает
sigmask, затем вызывается функция "select" и после этого
восстанавливается оригинальная маска.
Время ожидания
Используемые структуры времени определены в и
выглядят следующим как
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
и
struct timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
Иногда select вызывается с пустыми наборами (всеми тремя),
n равным нулю и непустым timeout для переносимой
реализации (portable) перехода в режим ожидания (sleep) на
периоды с точностью более секунды.
В Linux функция select изменяет timeout для отражения
времени, проведенного не в режиме ожидания; большая часть
других реализаций этого не делают. Это вызывает проблемы
как при переносе кода Linux, читающего timeout, на другие
операционные системы, так и при переносе на Linux кода,
использующего struct timeval для многократного вызова
select в цикле без его переинициализации. Во избежание
этого следует считать, что timeout не определен после
возврата из select.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном завершении select и pselect возвращают
количество описателей, находящихся в наборах, причем это
количество может быть равным нулю, если время ожидания на
исходе, а интересующие нас события так и не произошли.
При ошибке возвращаемое значение равно -1, а переменной
errno присваивается номер ошибки; наборы описателей и
значение timeout становятся неопределенными, поэтому при
ошибке нельзя полагаться на их значение.
КОДЫ ОШИБОК
EBADF В одном из наборов находится неверный файловый
описатель.
EINTR Был получен незаблокированный сигнал.
EINVAL n отрицательно.
ENOMEM Функция select не может выделить объем памяти для
внутренних таблиц.
ПРИМЕР
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");
return 0;
}
СООТВЕТСТВИЕ СТАНДАРТАМ
4.4BSD (функция select впервые появилась в 4.2BSD).
Обычно переносится с не-BSD систем и на них, если они
поддерживают уровень BSD-сокетов (включая варианты System
V). Однако, заметим, что варианты System V обычно
устанавливают значение переменной timeout перед выходом, а
вариант BSD - нет. Функция pselect определена в стандарте
IEEE Std 1003.1g-2000 (POSIX.1g) и в POSIX 1004.1-2001.
Она находится в библиотеке glibc2.1 и более свежих
версиях. Glibc2.0 имеет функцию с таким же именем,
которая не принимает параметр sigmask.
ЗАМЕЧАНИЯ
В соответствие с прототипами, в классическом случае для
использования select необходимо включать . В
случае POSIX 1003.1-2001 для использования select и pse-
lect необходимо включать . Libc4 и libc5 не
имеют файла заголовков ; в glibc 2.0 и более
поздних версиях он имеется. В glibc 2.0 прототип pselect
ошибочно определен всегда, в glibc 2.1-2.2.1 прототип pse-
lect определен только когда определено _GNU_SOURCE, в
glibc 2.2.2-2.2.4 прототип определен когда определено
_XOPEN_SOURCE и его значение равно 600 или более.
Несомненно, начиная с POSIX 1003.1-2001, этот прототип
включен по умолчанию.