Майкл Джонсон - Разработка приложений в среде Linux. Второе издание
- Название:Разработка приложений в среде Linux. Второе издание
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2007
- Город:Москва
- ISBN:978-5-8459-1143-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Майкл Джонсон - Разработка приложений в среде Linux. Второе издание краткое содержание
Книга известных профессионалов в области разработки коммерческих приложений в Linux представляет собой отличный справочник для широкого круга программистов в Linux, а также тех разработчиков на языке С, которые перешли в среду Linux из других операционных систем. Подробно рассматриваются концепции, лежащие в основе процесса создания системных приложений, а также разнообразные доступные инструменты и библиотеки. Среди рассматриваемых в книге вопросов можно выделить анализ особенностей применения лицензий GNU, использование свободно распространяемых компиляторов и библиотек, системное программирование для Linux, а также написание и отладка собственных переносимых библиотек. Изобилие хорошо документированных примеров кода помогает лучше усвоить особенности программирования в Linux.
Книга рассчитана на разработчиков разной квалификации, а также может быть полезна для студентов и преподавателей соответствующих специальностей.
Разработка приложений в среде Linux. Второе издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
15: return 1;
16: }
17:
18: if ( (fds[1] = open("p2", O_RDONLY)) < 0) {
19: perror("open p2");
20: return 1;
21: }
22:
23: fd = 0;
24: while (1) {
25: /* если данные доступны, прочитать и отобразить их */
26: i = read (fds[fd], buf, sizeof (buf) - 1);
27: if (i < 0) {
28: perror("read");
29: return 1;
30: } else if (!i) {
31: printf("канал закрыт\n");
32: return 0;
33: }
34:
35: buf[i] = '\0';
36: printf ("чтение: %s", buf);
37:
38: /* читать из другого файлового дескриптора */
39: fd = (fd + 1) % 2;
40: }
41: }
Хотя программа mpx-blocks
может считывать одновременно из обоих каналов, это не является особо эффективным. Она считывает из каждого канала по очереди. После запуска программа читает из первого файла, пока в нем доступны данные, второй файл игнорируется вплоть до возврата из read()
для первого файла. Как только произошел возврат, первый файл игнорируется вплоть до чтения данных из второго файла. Этот метод не поддерживает гладкое мультиплексирование данных. На рис. 13.1 показана программа mpx-blocks
во время выполнения.

Рис. 13.1. Примеры запуска мультиплексной передачи
13.1.1. Неблокируемый ввод-вывод
Как упоминалось в главе 11, неблокируемый файл можно определить с помощью системного вызова fcntl
. Если медленный файл неблокируемый, read()
сразу же возвращается. Если данные недоступны, она просто возвращает 0. Неблокируемый ввод- вывод предоставляет простое решение мультиплексирования, предотвращая блокирование файловых операций.
Показанная ниже модифицированная версия mpx-blocks
пользуется преимуществом неблокируемого ввода-вывода для более гладкого переключения между p1
и p2
.
1: /* mpx-nonblock.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;
12: int fd;
13:
14: /* открыть оба канала в неблокирующем режиме */
15: if ((fds[0] = open("p1", O_RDONLY | O_NONBLOCK)) < 0) {
16: perror("open p1");
17: return 1;
18: }
19:
20: if ((fds[1] = open("p2", O_RDONLY | O_NONBLOCK)) < 0) {
21: perror("open p2");
22: return 1;
23: }
24:
25: fd = 0;
26: while (1) {
27: /* если данные доступны, прочитать и отобразить их */
28: i = read(fds[fd], buf, sizeof (buf) - 1);
29: if ((i < 0) && (errno ! = EAGAIN)) {
30: perror("read");
31: return 1;
32: } else if (i > 0) {
33: buf[i] = '\0';
34: printf("чтение: %s", buf);
35: }
36:
37: /* читать из другого файлового дескриптора */
38: fd = (fd + 1) % 2;
39: }
40: }
Важное различие между mpx-nonblock
и mpx-blocks
состоит в том, что программа mpx-nonblock
не закрывается, когда один из каналов, из которого она считывает, закрыт. Неблокируемый read()
из канала без записывающих устройств возвращает 0 байт, из канала с таковыми, но без доступных данных read()
возвращает EAGAIN
.
Простое переключение неблокируемого ввода-вывода между дескрипторами файлов достается высокой ценой. Программа всегда опрашивает два файловых дескриптора для ввода — она никогда не блокируется. Постоянная работа программы приносит системе массу проблем, поскольку операционная система не может перевести процесс в режим ожидания (попробуйте запустить 10 копий mpx-nonblock
в своей системе и посмотрите, как это скажется на ее производительности).
13.1.2. Мультиплексирование с помощью poll()
Для эффективного мультиплексирования Linux предоставляет системный вызов poll()
, позволяющий процессу блокировать одновременно несколько файловых дескрипторов. Постоянно проверяя каждый файловый дескриптор, процесс создает отдельный системный вызов, определяющий, из каких файловых дескрипторов процесс будет читать, а на какие — записывать. Когда один или несколько таких файлов имеют данные, доступные для чтения, или могут принимать данные, записываемые в них, poll
() завершается, и приложение может считывать и записывать данные в дескрипторах, не беспокоясь о блокировке. После обработки этих файлов процесс создает еще один вызов poll()
, блокируемый до готовности файла. Ниже показано определение poll()
.
#include
int poll(struct pollfd * fds, int numfds, int timeout);
Последние два параметра очень просты; numfds
задает количество элементов в массиве, на который указывает первый параметр, a timeout
определяет, насколько долго poll()
должна ожидать события. Если в качестве тайм-аута задается 0, poll()
никогда не входит в состояние тайм-аута.
Первый параметр, fds
, описывает, какие файловые дескрипторы следует контролировать, и для каких типов ввода-вывода. Это указатель на массив структур struct pollfd
.
struct pollfd {
int fd; /* файловый дескриптор */
short events; /* ожидаемые события ввода-вывода */
short revents; /* происшедшие события ввода-вывода */
};
Первый элемент, fd
, является контролируемым файловым дескриптором, а элемент events описывает, какие типы событий подлежат мониторингу. Последний представляет собой один или несколько перечисленных флагов, объединенных с помощью логического "ИЛИ".
POLLIN |
Нормальные данные доступны для считывания из файлового дескриптора. |
POLLPRI |
Приоритетные (внешние) данные доступны для считывания. |
POLLOUT |
Файловый дескриптор может принимать записываемые на него данные. |
Элемент revents
структуры struct pollfd
заполняется системным вызовом poll()
и отражает состояние файлового дескриптора fd
. Это похоже на элемент events
, но вместо определения интересующих приложение событий ввода-вывода он определяет доступные такие типы. Например, если приложение контролирует канал как для чтения, так и для записи ( events
установлено в POLLIN | POLLOUT
), после успешного вызова poll()
в revents
устанавливается бит POLLIN
, если канал готов для чтения, и бит POLLOUT
, если в канале имеется пространство для записи дополнительных данных. Если верно и то, и другое, устанавливаются оба бита.
Существует несколько битов, которые ядро может установить в revents
, но которые невозможно установить в events
.
POLLERR |
В дескрипторе файла имеется ожидающая ошибка; выполнение системного вызова на файловом дескрипторе приведет к установке errno в подходящий код. |
POLLHUP |
Файл был отключен; в него больше невозможно ничего записывать (хотя могут остаться данные для считывания). Это происходит в случае отключения терминала либо закрытия удаленного конца канала или сокета. |
POLLNVAL |
Файловый дескриптор недоступен (он не относится к открытому файлу). |
Возвращаемое значение poll()
равно нулю в случае тайм-аута вызова, -1 в случае ошибки (например, fds
— неверный указатель; ошибки в самих файлах вызывают установку POLLERR
), или же положительное число, описывающее количество файлов с ненулевыми элементами revents.
Интервал:
Закладка: