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

发布于 2024-07-21 19:48:25 字数 1403 浏览 3 评论 0原文

我正在编写一个 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
  • 如果 string == "kill",则将该 fd 标记为死亡,并将其从列表中删除 (n--)
  • 如果 n == 0,则终止线程

在主程序中:

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

我看到的行为是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 (抱歉有点恶心)

I've got a C program I'm writing. Here's what it does:

  • Create n fifos using mkfifo
  • Open them for read (with the O_NONBLOCK flag set)
  • Open them for write
  • Spawn a thread

In the thread, run in a loop:

  • Create an fd_set of the file descriptors for all n fifos
  • Call select(n, &my_set, NULL, NULL, NULL)
  • For each fd ready for I/O (FD_ISSET(fd, &my_set)):
  • Read a string from the fd (read(fd, buf, buf_len))
  • Print the string
  • If string == "kill", mark the fd as dead and remove it from the list (n--)
  • If n == 0, terminate the thread

In the main program:

  • For i = 0 to n
  • Write to fds[i] with a string (write(fds[i], buf, buf_len))
  • For i = 0 to n
  • Write to fds[i] with the string "kill"
  • Join on the thread I created
  • Exit

The behavior I'm seeing is that select() will return once with a length of 1, being the first fd in the list. The second time through the loop, select will just sit there forever.

Here's my output:

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

The OS is Linux, in case it matters.

Link to the code: https://dl.getdropbox.com/u/188590/fifotest.c
(Sorry it's a bit heinous)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

趁微风不噪 2024-07-28 19:48:25

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

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

您还遇到一个问题,即向每个管道写入一个字符串加一个空字节,然后再写入一个字符串加一个空字节。 由于调度是不确定的,主程序实际上将其两个字符串写入每个 fifo,因此当侦听器线程开始读取它时,它会读取两个字符串。 当我打印长度时,我得到的总长度为 41 个 read (read_len),但每个 strlen() 的字符串长度是 31。换句话说,第一次阅读包含“kill”部分,但您在打印输出中没有注意到,因为第一条消息末尾有尾随空值。 因此,你在等待永远不会发生的事情。

As Lance Richardson said, the first problem is that you need to pass the number of the maximum file descriptor plus one, not the number of file descriptors.

You then have to clean up the housekeeping in the listener thread - I got most of the data, but ended up listening to 6 file descriptors, not 4. (The reported number was now the largest fd, not the number of file descriptors.)

You also have a problem that you write a string plus a null byte to each pipe, then a second string plus a null byte. Since the scheduling is non-deterministic, the main program actually gets to write both its strings to each fifo, so when the listener thread gets to read it, it reads both strings. When I printed out lengths, I got a total length of 41 read (read_len), but the length of the string per strlen() was 31. In other words, the first read included the 'kill' part, but you didn't notice in the printout because of the trailing null at the end of the first message. Hence you were waiting for that which will never happen.

清泪尽 2024-07-28 19:48:25

调用 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;

The first parameter in the call to select() should be the highest-numbered file descriptor plus 1, not the number of file descriptors in the fd_set.

Here's what I changed to fix this issue:

--- 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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文