Майкл Джонсон - Разработка приложений в среде Linux. Второе издание
- Название:Разработка приложений в среде Linux. Второе издание
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2007
- Город:Москва
- ISBN:978-5-8459-1143-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Майкл Джонсон - Разработка приложений в среде Linux. Второе издание краткое содержание
Книга известных профессионалов в области разработки коммерческих приложений в Linux представляет собой отличный справочник для широкого круга программистов в Linux, а также тех разработчиков на языке С, которые перешли в среду Linux из других операционных систем. Подробно рассматриваются концепции, лежащие в основе процесса создания системных приложений, а также разнообразные доступные инструменты и библиотеки. Среди рассматриваемых в книге вопросов можно выделить анализ особенностей применения лицензий GNU, использование свободно распространяемых компиляторов и библиотек, системное программирование для Linux, а также написание и отладка собственных переносимых библиотек. Изобилие хорошо документированных примеров кода помогает лучше усвоить особенности программирования в Linux.
Книга рассчитана на разработчиков разной квалификации, а также может быть полезна для студентов и преподавателей соответствующих специальностей.
Разработка приложений в среде Linux. Второе издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
В определенной системе при не очень высоком значении HIGH_FD
, равном 2, программа показала, что ядро за секунду может обрабатывать в четыре раза больше вызовов poll()
, чем вызовов select()
. При увеличении HIGH_FD
до 1000 эффективность poll()
становится в 40 раз выше, чем у select()
.
13.1.5. Мультиплексирование с помощью epoll
В версии 2.6 ядра Linux был предложен третий метод для мультиплексированного ввода-вывода по имени epoll
. Будучи более сложным, чем poll()
или select()
, epoll
ликвидирует узкие места, связанные с производительностью, которые характерны для обоих методов.
Оба системных вызова poll()
и select()
передают на проверку полный список файловых дескрипторов при каждом вызове. Каждый из этих дескрипторов должен быть обработан системным вызовом, даже если только один из них готов к чтению или записи. Когда проверяются десятки, сотни или тысячи файловых дескрипторов, эти системные вызовы превращаются в узкие места; ядро тратит много времени на выяснение того, какие именно файловые дескрипторы приложению необходимо проверить.
При использовании epoll
приложения обеспечивают ядро списком файловых дескрипторов для проверки с помощью одного системного вызова, а затем для проверки этих дескрипторов с помощью другого системного вызова. После создания списка ядро постоянно проверяет эти дескрипторы для событий, интересующих приложение [79] Фактически ядро устанавливает обратный вызов для каждого файла, а затем, когда происходит событие, активизирует обратный вызов. Этот механизм устраняет проблемы масштабируемости при очень большом количестве файловых дескрипторов, поскольку опрос не используется в каждой точке.
, а затем сообщает о событии. Как только приложение запрашивает у ядра файловые дескрипторы, готовые для дальнейшей обработки, ядро предоставляет список без необходимости проверки каждого файлового дескриптора.
Преимущества в плане производительности epoll
требуют более сложного, чем у poll()
или select()
, интерфейса системных вызовов. В то время как poll()
использует массив struct pollfd
для предоставления набора файловых дескрипторов, a select()
с той же целью — три разных структуры fd_set
, epoll
перемещает эти наборы файловых дескрипторов в ядро, а не хранит их в адресном пространстве программы. На каждый из этих наборов ссылаются с помощью дескриптора epoll
, являющегося файловым дескриптором, который можно применять только для системных вызовов epoll
. Новые дескрипторы epoll распределяются системным вызовом epoll_create()
.
#include
int epoll_create (int numDescriptors);
Единственный параметр numDescriptors
— это наилучшее предположение программы о том, на какое количество файловых дескрипторов будет ссылаться заново созданный дескриптор epoll
. Это не жесткий предел, это просто подсказка ядру для более точной инициализации его внутренних структур. epoll_create()
возвращает дескриптор epoll
, а когда программа заканчивает работу с дескриптором, его следует передать close()
, чтобы позволить ядру освободить память, используемую этим дескриптором.
Хотя дескриптор epoll
является файловым дескриптором, его следует применять только с двумя системными вызовами.
#include
int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents,
int timeout);
Большинство этих параметров используют структуру struct epoll_event
, которая определяется, как показано ниже.
#include
struct epoll_event {
int events;
union {
void * ptr;
int fd;
unsigned int u32;
unsigned long long u64;
} data;
};
Эта структура обслуживает три цели: определяет, какие типы событий следует проверять, определяет типы произошедших событий и ассоциирует отдельный элемент данных с файловым дескриптором. Поле events
предназначено для первых двух функций и является одной или несколькими перечисленными далее значениями, объединенными с помощью логического "ИЛИ" [80] EPOLLET — это еще одно значение, которое может иметь events , переключающее epoll с запуска уровнем на запуск фронтом сигнала. Эта тема выходит за рамки настоящей книги, и epoll , запускаемую фронтом, следует применять только в особых случаях.
.
EPOLLIN |
Определяет, что операция read() не блокируется; данные или уже готовы, или их уже не осталось для считывания. |
EPOLLOUT |
Связанный файл готов для записи. |
EPOLLPRI |
Файл имеет внешние данные, готовые для чтения. |
Второй элемент struct epoll_event, data
, представляет собой объединение, содержащее целое число (для хранения файлового дескриптора), указатель, а также 32- и 64-битные целые числа [81] Структура, показанная в тексте, предоставляет правильные размеры элементов на большинстве платформ, но они неправильны для машин, в которых int имеет 64 бита.
. Этот элемент данных хранится в epoll
и возвращается в программу всякий раз, когда происходит событие подходящего типа. Элемент data
— это единственный способ, с помощью которого программе нужно выяснить, какой файловый дескриптор необходимо обслужить; интерфейс epoll
не передает файловый дескриптор программе, в отличие от poll()
и select()
(если data
не содержит файловый дескриптор). Этот метод обеспечивает дополнительную гибкость приложениям, которые отслеживают файлы как нечто, более сложное, чем простые файловые дескрипторы.
Системный вызов epoll_ctl()
добавляет файловые дескрипторы к набору, на который ссылается дескриптор epfdepoll
, и удаляет их из него.
Второй параметр, op
, описывает, каким образом следует модифицировать набор файловых дескрипторов, и является одним из перечисленных ниже.
EPOLL_CTL_ADD |
Файловый дескриптор fd добавляется к набору файловых дескрипторов набором событий events . Если файловый дескриптор уже присутствует, он возвращает EEXIST . (Несколько потоков могут добавлять тот же файловый дескриптор к набору epoll более одного раза, но это действие ничего не меняет.) |
EPOLL_CTL_DEL |
Файловый дескриптор fd удаляется из контролируемого набора файловых дескрипторов. Параметр events должен указывать на struct epoll_event , но содержимое этой структуры игнорируется. (Это еще раз доказывает, что events должен быть допустимым указателем; он не может быть NULL .) |
EPOLL_CTL_MOD |
Системный вызов struct epoll_event для fd обновляется на основе информации, на которую указывает events . Это позволяет контролировать набор событий и обновлять элемент данных, ассоциируемый с файловым дескриптором, не создавая условий состязания. |
Последним системным вызовом epoll
является epoll_wait()
, который блокирует до тех пор, пока один или несколько контролируемых файловых дескрипторов не будут иметь данные для чтения или же не будут готовы к записи. Первым аргументом является дескриптор epoll
, а последний — тайм-аутом в секундах. Если файловые дескрипторы не готовы к обработке до истечения тайм-аута, epoll_wait()
возвращает 0
.
Интервал:
Закладка: