Майкл Джонсон - Разработка приложений в среде Linux. Второе издание
- Название:Разработка приложений в среде Linux. Второе издание
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2007
- Город:Москва
- ISBN:978-5-8459-1143-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Майкл Джонсон - Разработка приложений в среде Linux. Второе издание краткое содержание
Книга известных профессионалов в области разработки коммерческих приложений в Linux представляет собой отличный справочник для широкого круга программистов в Linux, а также тех разработчиков на языке С, которые перешли в среду Linux из других операционных систем. Подробно рассматриваются концепции, лежащие в основе процесса создания системных приложений, а также разнообразные доступные инструменты и библиотеки. Среди рассматриваемых в книге вопросов можно выделить анализ особенностей применения лицензий GNU, использование свободно распространяемых компиляторов и библиотек, системное программирование для Linux, а также написание и отладка собственных переносимых библиотек. Изобилие хорошо документированных примеров кода помогает лучше усвоить особенности программирования в Linux.
Книга рассчитана на разработчиков разной квалификации, а также может быть полезна для студентов и преподавателей соответствующих специальностей.
Разработка приложений в среде Linux. Второе издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
В отличие от неэффективного метода мультиплексирования входных и выходных данных из каналов, используемого ранее, poll()
довольно легко решает ту же проблему. Применяя poll()
к файловым дескрипторам одновременно для обоих каналов, мы знаем, что когда poll()
возвращается, один из каналов готов для чтения либо закрыт. Мы проверяем элемент revents
для обоих файловых дескрипторов, чтобы узнать, какие действия предпринять, и по завершении возвращаемся в вызов poll()
. Теперь большая часть времени тратится на блокирование вызова poll()
, а не на постоянную проверку файловых дескрипторов, использующих неблокируемый ввод-вывод, что значительно уменьшает нагрузку на систему. Ниже показан код mpx-poll
.
1: /* mpx-poll.с */
2:
3: #include
4: #include
5: #include
6: #include
7:
8: int main(void) {
9: struct pollfdfds[2];
10: char buf [4096];
11: int i, rc;
12:
13: /* открыть оба канала */
14: if ( (fds[0].fd = open("p1", O_RDONLY | O_NONBLOCK)) < 0) {
15: perror("open p1");
16: return 1;
17: }
18:
19: if ((fds[1].fd = open("p2", O_RDONLY | O_NONBLOCK)) < 0) {
20: perror("open p2");
21: return 1;
22: }
23:
24: /* начать чтение из обоих файловых дескрипторов */
25: fds[0].events = POLLIN;
26: fds[1].events = POLLIN;
27:
28: /* пока наблюдаем за одним из fds[0] или fds[1] */
29: while (fds[0].events || fds[1].events ) {
30: if (poll(fds, 2, 0) < 0) {
31: perror("poll");
32: return 1;
33: }
34:
35: /* проверить, какой из файловых дескрипторов
36: готов для чтения из него */
37: for (i = 0; i < 2; i++) {
38: if (fds[i].revents) {
39: /* fds[i] готов для чтения, двигаться дальше... */
40: rc = read(fds[i].fd, buf, sizeof(buf) - 1);
41: if (rc < 0) {
42: perror("read");
43: return 1;
44: } else if (!rc) {
45: /* этот канал закрыт, не пытаться
46: читать из него снова */
47: fds[i].events = 0;
48: } else {
49: buf[rc] = '\0';
50: printf("чтение : %s", buf);
51: }
52: }
53: }
54: }
55:
56: return 0;
57: }
13.1.3. Мультиплексирование с помощью select()
Системный вызов poll()
был изначально представлен как часть Unix-дерева System V. Усилиями разработчиков BSD та же основная проблема была решена похожим способом — предоставлением системного вызова select()
.
#include
int select(int numfds, fd_set * readfds, fd_set * writefds,
fd_set * exceptfds, struct timeval * timeout);
Три промежуточных параметра — readfds
, writefds
и exceptfds
— определяют, за какими файловыми дескрипторами необходимо следить. Каждый параметр — это указатель на fd_set
, структуру данных, позволяющую процессу определить произвольное количество файловых дескрипторов [74] Это похоже на тип sigset_t , используемый для шаблонов сигналов.
. Ею манипулируют с помощью перечисленных ниже макросов.
FD_ZERO(fd_set * fds); |
Очищает fds — в наборе не содержатся файловые дескрипторы. Этот макрос используется для инициализации структур fd_set . |
FD_SET(intfd, fd_set * fds); |
Добавляет fd к fd_set . |
FD_CLR(intfd, fd_set * fds); |
Удаляет fd из fd_set . |
FD_ISSET(int fd, fd_set * fds); |
Возвращает true , если fd содержится в установленном fds . |
Первый набор файловых дескрипторов select()
, readfds
, содержит перечень файловых дескрипторов, вызывающих возврат вызова select()
, когда они готовы для чтения [75] Когда сетевой сокет прослушивается ( listen() ) и готов к приему ( accept() ), считается, что он готов к считыванию для целей select() ; информацию о сокетах можно найти в главе 17.
или (для каналов и сокетов) когда процесс на другом конце файла закрыл его. Когда любой файловый дескриптор в writefds
готов к записи, select()
возвращается, exceptfds
содержит файловые дескрипторы для слежения за исключительными условиями. В Linux (так же, как и в Unix) это происходит только при поступлении внешних данных в сетевое подключение. В качестве любого из них можно указать NULL
, если тот или иной тип события вас не интересует.
Окончательный параметр, timeout
, определяет, насколько долго (в миллисекундах) вызову select()
необходимо ожидать какого-либо события. Это указывает на struct timeval
, которая выглядит следующим образом.
#include
struct timeval {
int tv_sec; /* секунды */
int tv_usec; /* микросекунды */
};
Первый элемент — tv_sec
— это количество оставшихся секунд, a tv_usec
— это количество оставшихся микросекунд. Если значением timeout
является NULL
, select()
блокируется до следующего события. Если он указывает на struct timeval
, содержащую 0 в обоих элементах, вызов select()
не блокируется. Он обновляет наборы файловых дескрипторов, чтобы определить, какой файловый дескриптор в настоящее время готов для чтения или записи, а затем немедленно возвращается.
Первый параметр, numfds
, вызывает наибольшие трудности. Он задает количество файловых дескрипторов (начиная с файлового дескриптора 0), которое может быть определено с помощью fd_sets
. Еще один (и, возможно, более легкий) способ поведения numfds
намного лучше максимального файлового дескриптора select()
[76] Если сравнить это с параметром numfds для poll() , то можно понять, почему возникают затруднения.
.
Поскольку Linux обычно позволяет каждому процессу иметь до 1024 файловых дескрипторов, numfds
избавляет ядро от необходимости просмотра всех 1024 файловых дескрипторов, которые может содержать каждая структура fd_set
, что улучшает показатели производительности.
После возврата три структуры fd_set
содержат файловые дескрипторы с задержкой входных данных, на которые можно произвести запись или которые находятся в исключительном состоянии. Вызов select()
в Linux возвращает общее количество элементов, установленных в трех структурах fd_set
, 0
в случае тайм-аута вызова либо -1
в случае ошибки. Однако многие системы Unix считают определенные файловые дескрипторы в возвращаемом значении только один раз, даже если они находятся как в readfds
, так и в writefds
, поэтому в целях переносимости лучше совершать проверку только тогда, когда возвращаемое значение больше 0
. Если возвращаемое значение равно -1
, не думайте, что структуры fd_set
остаются незатронутыми. Linux обновляет их только в случае, если select()
возвращает значение больше 0, однако некоторые системы Unix демонстрируют иное поведение.
Еще одним параметром, связанным с переносимостью, является timeout
. Ядра Linux [77] Кроме некоторых экспериментальных ядер серии 2.1.
обновляют его, чтобы отобразить количество времени, оставшегося до тайм-аута вызова select()
, но большинство других систем Unix его не обновляют [78] Когда Линус Торвальдс впервые реализовал select() , неспособность ядра BSD обновлять timeout была отмечена как ошибка на man-странице для select() . Вместо написания ошибочного кода Линус решил "исправить" эту ошибку. К сожалению, комитеты по стандартам одобрили поведение BSD.
. Однако другие системы не обновляют тайм-аут с целью соответствия более привычной реализации.
Интервал:
Закладка: