Этот код разрешает переносимые паузы длительностью менее секунды (это обеспечивает также библиотечная функция BSD usleep()
, но select()
намного более переносима). Например, usecsleep(500000)
вызывает паузу минимум на полсекунды.
Вызов select()
также используется для решения примера мультиплексирования каналов, с которым мы работали. Решение очень похоже на решение при использовании poll()
.
1: /* mpx-select.c */
2:
3: #include
4: #include
5: #include
6: #include
7:
8: int main(void) {
9: int fds[2];
10: char buf[4096];
11: int i, rc, maxfd;
12: fd_set watchset; /* fds для чтения */
13: fd_set inset; /* обновляется select() */
14:
15: /* открыть оба канала */
16: if ((fds[0] = open("p1", O_RDONLY | O_NONBLOCK)) < 0) {
17: perror("open p1");
18: return 1;
19: }
20:
21: if ((fds[1] = open("p2", O_RDONLY | O_NONBLOCK)) < 0) {
22: perror("open p2");
23: return 1;
24: }
25:
26: /* начать чтение из обоих файловых дескрипторов */
27: FD_ZERO(&watchset);
28: FD_SET(fds[0], &watchset);
29: FD_SET(fds[1], &watchset);
30:
31: /* найти максимальный файловый дескриптор */
32: maxfd = fds[0] > fds[1] ? fds[0] : fds[1];
33:
34: /* пока наблюдаем за одним из fds[0] или fds[1] */
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: }
Обладая одинаковой функциональностью, poll()
и select()
также имеют существенные отличия. Наиболее очевидным отличием является тайм-аут, поддерживающий миллисекундную точность для poll()
и микросекундную точность для select()
. В действительности же это отличие почти незначительно, поскольку ни один системный вызов не будет подготовлен с точностью до микросекунды.
Более важное отличие связано с производительностью. Интерфейс poll()
обладает несколькими свойствами, делающими его намного эффективнее, чем select()
.
1. При использовании select()
ядру необходимо проверить все файловые дескрипторы между 0
и numfds - 1
, чтобы убедиться, заинтересовано ли приложение в событиях ввода-вывода для этого файлового дескриптора. Для приложений с большим количеством открытых файлов это может привести к существенным затратам, поскольку ядро проверяет, какие именно файловые дескрипторы являются объектом интереса.