简体   繁体   English

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

[英]Reading from FIFO in C: select() doesn't return?

I've got a C program I'm writing. 我有一个C程序,我正在写。 Here's what it does: 这是它的作用:

  • Create n fifos using mkfifo 使用mkfifo创建n个fifos
  • Open them for read (with the O_NONBLOCK flag set) 打开它们进行读取(设置O_NONBLOCK标志)
  • 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 为所有n个FIFO创建文件描述符的fd_set
  • Call select(n, &my_set, NULL, NULL, NULL) 调用select(n,&my_set,NULL,NULL,NULL)
  • For each fd ready for I/O (FD_ISSET(fd, &my_set)): 对于每个准备好I / O的fd(FD_ISSET(fd,&my_set)):
    • Read a string from the fd (read(fd, buf, buf_len)) 从fd读取一个字符串(读取(fd,buf,buf_len))
    • Print the string 打印字符串
    • If string == "kill", mark the fd as dead and remove it from the list (n--) 如果string ==“kill”,将fd标记为dead并将其从列表中删除(n--)
    • If n == 0, terminate the thread 如果n == 0,则终止该线程

In the main program: 在主程序中:

  • For i = 0 to n 对于i = 0到n
    • Write to fds[i] with a string (write(fds[i], buf, buf_len)) 用字符串写入fds [i](写(fds [i],buf,buf_len))
  • For i = 0 to n 对于i = 0到n
    • Write to fds[i] with the string "kill" 用字符串“kill”写入fds [i]
  • 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. 我看到的行为是select()将返回一次长度为1,是列表中的第一个fd。 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. 操作系统是Linux,以防万一。

Link to the code: https://dl.getdropbox.com/u/188590/fifotest.c (Sorry it's a bit heinous) 链接到代码: https//dl.getdropbox.com/u/188590/fifotest.c (对不起,这有点令人发指)

Thanks, Nathan 谢谢,内森

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. 正如Lance Richardson所说,第一个问题是你需要传递最大文件描述符的数量加一,而不是文件描述符的数量。

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. 然后你必须清理监听器线程中的内务管理 - 我获得了大部分数据,但最终听到了6个文件描述符,而不是4个。 ( The reported number was now the largest fd, not the number of file descriptors. ) 报告的数字现在是最大的fd,而不是文件描述符的数量。

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. 由于调度是非确定性的,因此主程序实际上将其字符串写入每个fifo,因此当侦听器线程读取它时,它会读取两个字符串。 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. 当我打印出长度时,我的总长度为41( read_len ),但每个strlen()的字符串长度为31.换句话说,第一次读取包括'kill'部分,但是你没有由于第一条消息末尾的尾部空值,因此在打印输出中发出通知。 Hence you were waiting for that which will never happen. 因此,你在等待永远不会发生的事情。

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. select()调用中的第一个参数应该是编号最大的文件描述符加1,而不是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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM