Чтение онлайн

ЖАНРЫ

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

35: while (FD_ISSET(fds[0], &watchset) ||

36: FD_ISSET(fds[1], &watchset)) {

37: /* здесь копируем watchset, потому что select обновляет его */

38: inset = watchset;

39: if (select(maxfd + 1, &inset, NULL, NULL, NULL) < 0) {

40: perror("select");

41: return 1;

42: }

43:

44: /* проверить, какой из файловых дескрипторов

45:
готов для чтения из него */

46: for (i = 0; i < 2; i++) {

47: if (FD_ISSET(fds[i], &inset )) {

48: /* fds[i] готов для чтения, двигаться дальше... */

49: rc = read(fds[i], buf, sizeof (buf) - 1);

50: if (rc < 0) {

51: perror("read");

52: return 1;

53: } else if (!rc) {

54: /* этот канал закрыт, не пытаться

55: читать из него снова */

56: close(fds[i]);

57: FD_CLR(fds[i], &watchset);

58: } else {

59: buf[rc] = '\0';

60: printf("чтение: %s", buf);

61: }

62: }

63: }

64: }

65:

66: return 0;

67: }

13.1.4. Сравнение

poll
и
select

Обладая одинаковой функциональностью,

poll
и
select
также имеют существенные отличия. Наиболее очевидным отличием является тайм-аут, поддерживающий миллисекундную точность для
poll
и микросекундную точность для
select
. В действительности же это отличие почти незначительно, поскольку ни один системный вызов не будет подготовлен с точностью до микросекунды.

Более важное отличие связано с производительностью. Интерфейс

poll
обладает несколькими свойствами, делающими его намного эффективнее, чем
select
.

1. При использовании

select
ядру необходимо проверить все файловые дескрипторы между
0
и
numfds - 1
, чтобы убедиться, заинтересовано ли приложение в событиях ввода-вывода для этого файлового дескриптора. Для приложений с большим количеством открытых файлов это может привести к существенным затратам, поскольку ядро проверяет, какие именно файловые дескрипторы являются объектом интереса.

2. Набор файловых дескрипторов передается ядру как битовая карта для

select
и как список для
poll
. Сложные битовые операции, необходимые для проверки и установки структур данных
fd_set
, менее эффективны, чем простые проверки, требуемые для
struct pollfd
.

3. Поскольку ядро переписывает структуры данных, передаваемые

select
, приложение вынуждено сбрасывать эти структуры каждый раз перед вызовом
select
.
С
poll
результаты ядра ограничены элементом
revents
, что устраняет потребность в восстановлении структур данных после каждого вызова.

4. Использование структуры, основанной на множествах (например,

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

Единственным преимуществом

select
перед
poll
является лучшая переносимость в старые системы. Поскольку небольшое количество таких реализаций все еще используется, следует применять
select
, прежде всего, для понимания и эксплуатации существующих кодовых баз.

Следующая короткая программа, подсчитывающая количество системных вызовов в секунду, демонстрирует, насколько

poll
эффективнее
select
.

 1: /* select-vs-poll.с */

 2:

 3: #include <fcntl.h>

 4: #include <stdio.h>

 5: #include <sys/poll.h>

 6: #include <sys/select.h>

 7: #include <sys/signal.h>

 8: #include <unistd.h>

 9:

10: int gotAlarm;

11:

12: void catch(int sig) {

13: gotAlarm = 1;

14: }

15:

16: #define HIGH_FD 1000

17:

18: int main(int argc, const char ** argv) {

19: int devZero;

20: int count;

21: fd_set select Fds;

22: struct pollfd pollFds;

23:

24: devZero = open("/dev/zero", O_RDONLY);

25: dup2(devZero, HIGH_FD);

26:

27: /* с помощью signal выяснить, когда время истекло */

28: signal(SIGALRM, catch);

29:

30: gotAlarm =0;

31: count = 0;

32: alarm(1);

33: while (!gotAlarm) {

34: FD_ZERO(&selectFds);

35: FD_SET(HIGH_FD, &selectFds);

36:

37: select(HIGH_FD + 1, &selectFds, NULL, NULL, NULL);

Поделиться с друзьями: