C 中从 FIFO 读取:select() 不返回?

问题描述 投票:0回答:2

我正在编写一个 C 程序。它的作用如下:

  • 使用 mkfifo 创建 n 个 fifo
  • 打开它们进行读取(设置 O_NONBLOCK 标志)
  • 打开它们进行写入
  • 产生一个线程

在线程中,循环运行:

  • 为所有 n 个 fifo 创建文件描述符的 fd_set
  • 调用 select(n, &my_set, NULL, NULL, NULL)
  • 对于每个准备好 I/O 的 fd (FD_ISSET(fd, &my_set)):
  • 从fd中读取字符串(read(fd, buf, buf_len))
  • 打印字符串
  • 如果 string == "kill",则将 fd 标记为死亡并将其从列表中删除 (n--)
  • 如果 n == 0,则终止线程

在主程序中:

  • 对于 i = 0 到 n
  • 用字符串写入 fds[i] (write(fds[i], buf, buf_len))
  • 对于 i = 0 到 n
  • 用字符串“kill”写入fds[i]
  • 加入我创建的线程
  • 退出

我看到的行为是 select() 将返回一次,长度为 1,成为列表中的第一个 fd。第二次循环时,选择将永远坐在那里。

这是我的输出:

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 (抱歉,有点令人发指)

c linux posix-select
2个回答
4
投票

正如 Lance Richardson 所说,第一个问题是你需要传递最大文件描述符的数量加一,而不是文件描述符的数量。

然后你必须清理监听器线程中的内务工作 - 我获得了大部分数据,但最终监听了 6 个文件描述符,而不是 4 个。报告的数字现在是最大的 fd,而不是文件描述符的数量)文件描述符。)

您还遇到一个问题,即向每个管道写入一个字符串和一个空字节,然后再写入第二个字符串和一个空字节。由于调度是不确定的,主程序实际上将其两个字符串写入每个 fifo,因此当侦听器线程开始读取它时,它会读取两个字符串。当我打印出长度时,我得到的总长度为 41 个读取(

read_len
),但是每个
strlen()
的字符串长度是 31。换句话说,第一次读取包括“kill”部分,但你没有由于第一条消息末尾的尾随 null,因此在打印输出中没有注意到。因此,你在等待永远不会发生的事情。


2
投票

调用 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;
© www.soinside.com 2019 - 2024. All rights reserved.