Майкл Джонсон - Разработка приложений в среде Linux. Второе издание
- Название:Разработка приложений в среде Linux. Второе издание
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2007
- Город:Москва
- ISBN:978-5-8459-1143-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Майкл Джонсон - Разработка приложений в среде Linux. Второе издание краткое содержание
Книга известных профессионалов в области разработки коммерческих приложений в Linux представляет собой отличный справочник для широкого круга программистов в Linux, а также тех разработчиков на языке С, которые перешли в среду Linux из других операционных систем. Подробно рассматриваются концепции, лежащие в основе процесса создания системных приложений, а также разнообразные доступные инструменты и библиотеки. Среди рассматриваемых в книге вопросов можно выделить анализ особенностей применения лицензий GNU, использование свободно распространяемых компиляторов и библиотек, системное программирование для Linux, а также написание и отладка собственных переносимых библиотек. Изобилие хорошо документированных примеров кода помогает лучше усвоить особенности программирования в Linux.
Книга рассчитана на разработчиков разной квалификации, а также может быть полезна для студентов и преподавателей соответствующих специальностей.
Разработка приложений в среде Linux. Второе издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Два промежуточных параметра определяют буфер для ядра, в который можно копировать структуры struct epoll_event
. Параметр events
указывает на буфер, maxevents
определяет, какое количество структур struct epoll_event
помещается в буфер, а возвращаемое значение сообщает программе количество структур, помещенных в этот буфер (пока вызов не попадет в состояние тайм-аута либо не произойдет ошибка).
Каждый системный вызов struct epoll_event
сообщает программе полное состояние контролируемого файлового дескриптора. Элемент events
может иметь установленные флаги EPOLLIN
, EPOLLOUT
или EPOLLPRI
, а также два новых флага, которые описаны ниже.
EPOLLERR |
С файлом связано ожидающее состояние ошибки; это случается, если ошибка происходит в сокете, когда приложение не считывает из него или не записывает в него. |
EPOLLHUP |
Файловый дескриптор завис; в главе 10 дана информация о том, когда это обычно происходит. |
На первый взгляд это все может показаться сложным, но на самом деле это очень похоже на работу poll()
. Вызов epoll_create()
— это то же, что и распределение массива struct pollfd
, a epoll_ctl()
— это то же, что и инициализация элементов этого массива. Главный цикл, обрабатывающий файловые дескрипторы, использует epoll_wait()
вместо системного вызова poll()
, а close()
аналогичен освобождению памяти, занимаемой массивом struct pollfd
. Эти параллели помогают переписывать с применением epoll
программы мультиплексирования, которые изначально были реализованы с помощью poll()
или select()
.
Интерфейс epoll
предлагает еще одну возможность, которую невозможно сравнить с poll()
или select()
. Поскольку дескриптор epoll
в действительности является файловым дескриптором (вот почему его можно передавать close()
), имеется возможность контролировать дескриптор epoll
как часть еще одного дескриптора epoll
либо через poll()
или select()
. Дескриптор epoll
будет готов к чтению из любого места, а вызов epoll_wait()
вернет события.
В окончательном решении проблемы мультиплексирования каналов, предложенном в данном разделе, используется epoll
. Оно очень похоже на другие примеры, вот только определенная часть кода инициализации перемещена в новую функцию addEvent()
для предотвращения нежелательного удлинения программы.
1: /* mpx-epoll.c */
2:
3: #include
4: #include
5: #include
6: #include
7: #include
8:
9: #include
10:
11: void addEvent(int epfd, char * filename) {
12: int fd;
13: struct epoll_event event;
14:
15: if ((fd = open (filename, O_RDONLY | O_NONBLOCK)) < 0) {
16: perror("open");
17: exit(1);
18: }
19:
20: event.events = EPOLLIN;
21: event.data.fd = fd;
22:
23: if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event)) {
24: perror("epoll_ctl(ADD)");
25: exit(1);
26: }
27: }
28:
29: int main(void) {
30: char buf[4096];
31: int i, rc;
32: int epfd;
33: struct epoll_event events[2];
34: int num;
35: int numFds;
36:
37: epfd = epoll_create(2);
38: if (epfd < 0) {
39: perror("epoll_create");
40: return 1;
41: }
42:
43: /* открыть оба канала и добавить их в набор epoll */
44: addEvent(epfd, "p1");
45: addEvent(epfd, "p2");
46:
47: /* продолжать, пока есть один или более файловых дескрипторов
48: для слежения */
49: numFds = 2;
50: while (numFds) {
51: if ((num = epoll_wait(epfd, events,
52: sizeof(events) / sizeof(* events),
53: -1)) <= 0) {
54: perror("epoll_wait");
55: return 1;
56: }
57:
58: for (i = 0; i < num; i++) {
59: /* events[i].data.fd готов для чтения */
60:
61: rc = read(events[i].data.fd, buf, sizeof(buf) - 1);
62: if (rc < 0) {
63: perror("read");
64: return 1;
65: } else if (!rc) {
66: /* этот канал закрыт, не пытаться
67: читать из него снова */
68: if (epoll_ctl(epfd, EPOLL_CTL_DEL,
69: events[i].data.fd, &events[i])) {
70: perror("epoll_ctl (DEL)");
71: return 1;
72: }
73:
74: close(events[i].data.fd);
75:
76: numFds--;
77: } else {
78: buf[rc] = '\0';
79: printf("чтение: %s", buf);
80:
81: }
82: }
83:
84: close(epfd);
85:
86: return 0;
87: }
13.1.6 Сравнение poll()
и epoll
Методы poll()
и epoll
существенно отличаются; poll()
хорошо стандартизован, но плохо масштабируется, в то время как epoll
существует только в Linux, но очень хорошо масштабируется. Приложения, наблюдающие за небольшим количеством файловых дескрипторов и переносимости величин, должны использовать poll()
, но любому приложению, которому необходимо контролировать большое количество дескрипторов, лучше применять epoll
, даже если ему нужно поддерживать poll()
для других платформ.
Отличия в производительности двух методов поразительны. Чтобы продемонстрировать, насколько лучше масштабируется epoll
, в коде poll-vs-epoll.с
измеряется количество системных вызовов poll()
и epoll_wait()
, которые можно создать за одну секунду для наборов файловых дескрипторов разных размеров (количество файловых дескрипторов для помещения в набор задается в командной строке). Каждый файловый дескриптор ссылается на считывающую часть канала, и они создаются с помощью dup2()
.
В табл. 13.1 суммируются результаты запуска poll-vs-epoll.с
для установленных размеров диапазоном от одного до 100 000 файловых дескрипторов [82] Эту программу необходимо запускать от имени root для наборов, содержащих более 1000 дескрипторов.
. В то время как количество системных вызовов в секунду резко падает для poll()
, оно остается почти постоянным для epoll
[83] Настоящее тестирование не гарантирует статистическую точность. Был проведен лишь один тестовый прогон, поэтому результаты поначалу будут неустойчивыми, что, однако, исчезнет после большого количества повторов.
. Как поясняет эта таблица, epoll
добавляет в систему намного меньше нагрузки, чем poll()
, и в результате гораздо лучше масштабируется.
Таблица 13.1. Результаты сравнения poll()
и epoll()
Файловые дескрипторы | poll() |
epoll() |
---|---|---|
1 |
310063 |
714848 |
10 |
140842 |
726108 |
100 |
25866 |
726659 |
1000 |
3343 |
729072 |
5000 |
612 |
718424 |
10000 |
300 |
730483 |
25000 |
108 |
717097 |
50000 |
38 |
729746 |
100000 |
18 |
712301 |
1: /* poll-vs-epoll.с */
Интервал:
Закладка: