调用“system”调用mpiexec后,STDIN似乎被打破了

时间:2013-01-05 01:35:41

标签: system stdin readline fork mpiexec

这是我在这里发表的第一篇文章,请原谅任何格式问题。

我有一个交互式程序,它产生外部进程并监视它们的IO。事情很好,直到我用“mpiexec”产生一些东西,之后STDIN似乎打破了。

我意识到这对于大多数人来说很难重现,但是如果有人看到任何明显的或知道这个问题的话......请帮忙!

这是一个片段:

int main( ... )
{
  std::string choice;
  while(std::getline(std::cin,choice)){
     if(!choice.empty()){
       if(choice == "Parallel"){
        system("mpiexec ./aprogram");
       }
       if(choice == "Serial"){
        system("./aprogram");
       }
       // Now the external process is done... so far, so good
       std::cout << "Program is done. Press ENTER to continue." 
                 << std::endl;
       // This next line *works* if the external process was serial
       // But *fails* when "mpiexec" was invoked 
       std::getline(std::cin,choice);
       if(std::cin.eof()){
         std::cout << "STDIN has been closed." << std::endl;
         exit(1);
       }
     }
  }
} 

我尝试了各种各样的 lot ,例如管道,显式分叉,细致的描述符管理。最奇怪的是,如果我复制并保存stdin然后在“mpiexec”返回后恢复它,那么我不再在std :: cin上获得EOF,而是std :: getline(std :: cin,... )不再阻止!该程序进入无限循环,在std :: readline调用中读取std :: cin的零字节。

如果,当外部进程在mpiexec下运行时,我将一堆数据堆叠到std :: cin中(例如通过输入),然后对std :: readline的后续调用正确地解析了我所滞留的数据行在那里,但是再次......一旦完成读取数据,它就会继续进入无限循环(即,即使没有数据要读取,也不会阻塞std :: readline(std :: cin,..)呃。太烦人了。

非常感谢任何帮助。

干杯!

2 个答案:

答案 0 :(得分:1)

我想我已经解决了你的问题,对我来说,串口或并口的调用被阻止了,我认为这是std :: cin.eof()测试,

  std::getline(std::cin,choice);
  if(std::cin.eof()){         
     td::cout << "STDIN has been closed." << std::endl;
     exit(1);
   }

但是,将其更改为std :: cin.get(),对于并行运行和串行运行都非常有用。

   if(std::cin.get()) {
     std::cout << "STDIN has been closed." << std::endl;
     exit(1);
   }

适用于我的系统。

答案 1 :(得分:0)

修改:错误报告已moved to GitHub

好的,这不是一个真正的答案,但显然没有足够的声誉来评论这个问题。

我和我的同事遇到了这个问题,并对其进行了追踪。你必须跳过一大堆箍才能在mpich bug report上添加评论,但我不希望我的发现消失在以太中,所以我在这里添加它们。 (如果有人在阅读此文件时有一个mpich Trac登录,那么如果您可以将此信息添加到故障单中,那就太棒了。)

Mpich确实似乎有一个错误,它在常见模式下在O_NONBLOCK的stdout / stderr文件描述符上设置mpirun标志。 mpirun退出后,这些设置会停留。但是,此错误通常不会浮出水面,因为bash在运行的每个命令之后都有代码可以关闭其附加流的非阻塞标志

mpirun中直接负责的代码位于alloc_fwd_hash中的src/pm/hydra/utils/sock.sock.c。它由src/pm/hydra/tools/bootstrap/external/external_common_launch.c函数中HYDT_bscd_common_launch_procs之类的地方的代码触发,其中有一些解复用程序注册步骤涉及最终调用HYDT_bscu_stdio_cb函数的回调alloc_fwd_hash。还有一些其他类似的代码片段也设置了HYDT_bscu_stdio_cb回调,并且通过我阅读代码,应该触发相同的问题。我不太了解mpich了解哪一块有问题,但我相信mpich将TTY文件描述符设置为非阻塞模式是不合适的。

您可以使用Homebrew版本的bash在OS X上运行mpirun来触发此错误。 Homebrew的bash是版本4.4,由于我不完全清楚的原因,似乎没有激活清除O_NONBLOCK标志的代码段。 OSX上的bash的默认版本是版本3, 清除该标志,防止错误出现。 Macports版本的Bash 4也表明了这个错误。