【问题标题】:select failing with C program but not shell选择使用 C 程序但不是 shell 失败
【发布时间】:2010-05-03 09:44:30
【问题描述】:

我有一个父子进程,父进程可以读取子进程的输出并发送到子进程的输入。到目前为止,使用 shell 脚本,测试输入和输出数据的命令一切正常。我刚刚用一个简单的 C 程序进行了测试,但无法让它工作。这是 C 程序:

#include <stdio.h>

int main( void ) {
  char stuff[80];
  printf("Enter some stuff:\n");
  scanf("%s", stuff);

  return 0;
}

C 程序的问题是我的选择无法从子 fd 读取,因此程序无法完成。这是执行选择的位..

//wait till child is ready
fd_set set;
struct timeval timeout;

FD_ZERO( &set ); // initialize fd set
FD_SET( PARENT_READ, &set ); // add child in to set
timeout.tv_sec = 3;
timeout.tv_usec = 0;

int r = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
if( r < 1 ) { // we didn't get any input
    exit(1);
}

有谁知道为什么 C 程序而不是 shell 程序会发生这种情况?

编辑:我应该指出子进程在参数上调用 exec,所以我无法访问它。

【问题讨论】:

    标签: c process select-function


    【解决方案1】:

    问题在于子进程正在完全缓冲输出,因为它正在写入管道而不是终端。使用setvbuf强制行缓冲或非缓冲模式,或者在printf之后给子进程添加显式fflush,或者使用Expect附带的unbuffer程序来欺骗子进程的libc认为程序是交互式工作。

    【讨论】:

    • 很好的电话回复setvbuf;希望你不介意我采纳这个建议。
    • @Charles:大约 5 年前有一段时间,这是 Tcl 社区新手的一个标准问题(“为什么我的子进程不起作用?!”),我上面的回答是我们告诉他们的基本蒸馏。 (嗯,使用完整的 Expect 是我们当时更喜欢的真正解决方案,但这不会作为这个 Q 的答案。)
    • 子进程正在使用 exec,所以 fflush() 并不是一个真正的选择。我尝试使用 setvbuf(stdout,(char*)NULL,_IONBF,0);在执行之前的孩子身上,但这似乎不起作用。你知道为什么吗?
    • 那些必须子进程的实现中,通常在main的开头。如果这在实践中是不可能的(例如,因为您无权访问源或无法更改它),那么您 需要 我提到的 unbuffer,它对 /dev/ 做了不敬的事情pty 系统来欺骗“真正的”子进程。
    • @Gary:顺便说一句,如果可能的话,您真的不想编写自己的 /dev/pty 处理程序代码。使用别人的。
    【解决方案2】:

    在阻止 C 程序中的输入之前刷新您的标准输出。

    fflush(stdout);
    

    在 shell 中,这通常是隐含的。

    或者,您可以使用setvbuf() 禁用缓冲(或启用行缓冲)。这必须在写入任何数据之前调用:

    setvbuf(stdout, NULL, _IONBF, 0)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多