Чтение из FIFO в C: select () не возвращается? - PullRequest
4 голосов
/ 23 мая 2009

У меня есть программа на C, которую я пишу. Вот что он делает:

  • Создание n fifos с использованием mkfifo
  • Открыть их для чтения (с установленным флагом O_NONBLOCK)
  • Открыть их для записи
  • порождение темы

В потоке запустить в цикле:

  • Создать fd_set файловых дескрипторов для всех n fifos
  • выбор вызова (n, & my_set, NULL, NULL, NULL)
  • Для каждого fd, готового к вводу / выводу (FD_ISSET (fd, & my_set)):
    • Чтение строки из fd (чтение (fd, buf, buf_len))
    • Распечатать строку
    • Если строка == "kill", пометьте fd как мертвый и удалите его из списка (n -)
    • Если n == 0, прекратить поток

В основной программе:

  • Для i = 0 до n
    • Запись в fds [i] со строкой (запись (fds [i], buf, buf_len))
  • Для i = 0 до n
    • Запись в fds [i] со строкой "kill"
  • Присоединяйтесь к созданной мной теме
  • Выход

Поведение, которое я вижу, состоит в том, что select () вернется один раз с длиной 1, являясь первым fd в списке. Во второй раз в цикле select будет просто сидеть там вечно.

Вот мой вывод:

thread created
Waiting on 4 file descriptors
> Wrote 'Hello to target 0 from writer 0' to 0
> Wrote 'Hello to target 0 from writer 1' to 1
> Wrote 'Hello to target 1 from writer 0' to 2
> Wrote 'Hello to target 1 from writer 1' to 3
> Sending kill to 0:0 (#0)
> Sending kill to 0:1 (#1)
> Sending kill to 1:0 (#2)
> Sending kill to 1:1 (#3)
< Got string: 'Hello to target 0 from writer 0'
Waiting on 4 file descriptors
^C

Операционная система Linux, если это имеет значение.

Ссылка на код: https://dl.getdropbox.com/u/188590/fifotest.c (Извините, это немного отвратительно)

Спасибо, Nathan

Ответы [ 2 ]

4 голосов
/ 23 мая 2009

Как сказал Ланс Ричардсон, первая проблема заключается в том, что вам нужно передать число максимального дескриптора файла плюс один, а не количество дескрипторов файла.

Затем вы должны очистить домашнюю работу в потоке слушателя - я получил большую часть данных, но в итоге прослушал 6 файловых дескрипторов, а не 4. ( Сообщенный номер был теперь самый большой fd, а не количество файловых дескрипторов. )

У вас также проблема в том, что вы записываете строку плюс нулевой байт в каждый канал, затем вторую строку плюс нулевой байт. Поскольку планирование является недетерминированным, основная программа фактически записывает обе свои строки в каждое fifo, поэтому, когда поток слушателя получает возможность прочитать его, он читает обе строки. Когда я распечатал длины, я получил общую длину 41 чтения (read_len), но длина строки на strlen() была 31. Другими словами, первое чтение включало часть «kill», но вы не не заметить в распечатке из-за завершающего нуля в конце первого сообщения. Следовательно, вы ждали того, что никогда не случится.

2 голосов
/ 23 мая 2009

Первым параметром в вызове select () должен быть дескриптор файла с наибольшим номером плюс 1, а не количество дескрипторов файла в наборе fd_set.

Вот что я изменил, чтобы исправить эту проблему:

--- fifotest-1.c        2009-05-22 23:44:03.000000000 -0400
+++ fifotest.c  2009-05-22 23:34:00.000000000 -0400
@@ -34,19 +34,22 @@
     sim_arg_t* ifs = arg;
     uint32_t num_ifs;
     uint32_t select_len;
+    int maxfd;

        num_ifs = ifs->num_ifs;
     while (num_ifs > 0) {
                FD_ZERO (&set);
                select_len = 0;
-               for (i = 0; i < ifs->num_ifs; ++i) {
+               for (maxfd=0, i = 0; i < ifs->num_ifs; ++i) {
                        if (ifs->if_list[i].valid) {
                                FD_SET(ifs->if_list[i].fh, &set);
-                               ++select_len;
+                               if (ifs->if_list[i].fh > maxfd)
+                                   maxfd = ifs->if_list[i].fh;
+                               select_len++;
                        }
                }
                printf("Waiting on %d file descriptors\n", select_len);
-               ret = select(select_len, &set, NULL, NULL, NULL);
+               ret = select(maxfd+1, &set, NULL, NULL, NULL);
                if (ret < 0) {
                        fprintf(stderr, "Select returned error!\n");
                        continue;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...