Читаем UNIX: разработка сетевых приложений полностью

В листинге 3.12 приведена более быстрая версия функции readline, использующая свой собственный буфер (а не буферизацию stdio). Основное достоинство этого буфера состоит в его открытости, благодаря чему вызывающий процесс всегда знает, какие именно данные уже приняты. Несмотря на это, использование readline все равно может вызвать проблемы, как мы увидим в разделе 6.3. Системные функции типа select ничего не знают о внутреннем буфере readline, поэтому неаккуратно написанная программа с легкостью может очутиться в состоянии ожидания в вызове select, при том, что данные уже будут находиться в буферах readline. По этой причине сочетание вызовов readn и readline не будет работать так, как этого хотелось бы, пока функция readn не будет модифицирована с учетом наличия внутреннего буфера.

Листинг 3.12. Улучшенная версия функции readline

//lib/readline.c

 1 #include "unp.h"

 2 static int read_cnt;

 3 static char *read_ptr;

 4 static char read_buf[MAXLINE];

 5 static ssize_t

 6 my_read(int fd, char *ptr)

 7 {

 8  if (read_cnt <= 0) {

 9   again:

10   if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {

11    if (errno == EINTR)

12     goto again;

13    return(-1);

14   } else if (read_cnt == 0)

15   return(0);

16   read_ptr = read_buf;

17  }

18  read_cnt--;

19  *ptr = *read_ptr++;

20  return(1);

21 }

22 ssize_t

23 readline(int fd, void *vptr, size_t maxlen)

24 {

25  ssize_t n, rc;

26  char c, *ptr;

27  ptr = vptr;

28  for (n = 1; n < maxlen; n++) {

29   if ((rc = my_read(fd, &c)) == 1) {

30    *ptr++ = c;

31    if (c== '\n')

32     break; /* Записан символ новой строки, как в fgets() */

33   } else if (rc == 0) {

34    *ptr = 0;

35    return(n - 1); /* EOF, считано n-1 байт данных */

36   } else

37    return(-1); /* ошибка, read() задает значение errno */

38  }

39  *ptr = 0; /* завершающий нуль, как в fgets() */

40  return(n);

41 }

42 ssize_t

43 readlinebuf(void **vptrptr)

44 {

45  if (read_cnt)

46   *vptrptr = read_ptr;

47  return(read_cnt);

48 }

2-21 Внутренняя функция my_read считывает до MAXLINE символов за один вызов и затем возвращает их по одному.

29 Единственное изменение самой функции readline заключается в том, что теперь она вызывает функцию my_read вместо read.

42-48 Новая функция readlinebuf выдает сведения о состоянии внутреннего буфера, что позволяет вызывающим функциям проверить, нет ли в нем других данных, помимо уже принятой строки.

ПРИМЕЧАНИЕ

К сожалению, использование переменных типа static в коде readline.c для поддержки информации о состоянии при последовательных вызовах приводит к тому, что функция больше не является безопасной в многопоточной системе (thread-safe) и повторно входимой (reentrant). Мы обсуждаем это в разделах 11.18 и 26.5. Мы предлагаем версию, безопасную в многопоточной системе, основанную на собственных данных программных потоков, в листинге 26.5.

<p>3.10. Резюме</p>
Перейти на страницу:

Все книги серии Мастер-класс

Секреты резьбы по дереву
Секреты резьбы по дереву

Изделия из древесины и материалов, имитирующих ее текстуру, привычным образом окружают нас в повседневной жизни, поэтому мы относимся к ней как к чему-то обыденному. Но как только ее коснется умелая рука мастера резьбы по дереву, рождается произведение искусства и раскрываются такие качества древесины, как богатая фактура, разнообразие цветов, особая теплота. Эта книга поможет читателю открыть для себя удивительный мир творчества и познать секреты резьбы по дереву. Автор надеется, что начинающие резчики найдут в ней интересный и полезный материал, который позволит им стать мастерами. В приложении представлены рисунки орнаментов и различных узоров, которые на первых порах можно копировать, а по мере приобретения навыка на их основе разрабатывать свои образцы.

Галина Алексеевна Серикова

Сделай сам / Хобби и ремесла / Руководства / Дом и досуг / Словари и Энциклопедии

Похожие книги