【问题标题】:Ordering problem when using Ruby popen2 to interact with C++ iostreams使用 Ruby popen2 与 C++ iostream 交互时的排序问题
【发布时间】:2011-05-25 17:13:12
【问题描述】:

我正在使用 Open3 的 popen2 与一个简单的 C++ 程序的 iostream 进行交互。我的理解是 std::cin 和 std::cout 是独立的,但是我的 popen2 块的 IO 对象读/写调用的顺序似乎有所不同。我的 C++ 程序是:

int main(int argc, char** argv) {
  std::string input;
  std::cout<<"EXECUTE TASK"<<std::endl;
  std::cin>>input;
  std::cout<<"END"<<std::endl;
}

我的 ruby​​ 脚本是:

require 'open3'
expected_string = "EXECUTE TASK"
Open3.popen2('~/Sandbox/a.out') { |stdin, stdout|
  stdin.write('\n')
  stdin.close
  results = stdout.readlines
  puts results
}

以上工作正常,但如果我将stdout.readlines 移动到stdin.close 之前,ruby 脚本将挂起。我的意图是如果 C++ 程序首先将 expected_string 写入标准输出,则有条件地将 \n 写入标准输入,但我不得不在执行 readlines 之前关闭标准输入流。就像我说的,我的理解是两个流是独立的,popen2 返回的文件描述符似乎也是独立的,那么为什么顺序很重要?

感谢任何帮助。谢谢。

具有我想要完成的全部范围的解决方案(有人可能会觉得这很有帮助):

int main(int argc, char** argv) {
    std::string input;

    std::cout<<"1"<<std::endl;
    std::cout<<"2"<<std::endl;
    std::cout<<"3"<<std::endl;
    std::cout<<"4"<<std::endl;
    std::cout<<"5"<<std::endl;
    std::cout<<"EXECUTE TASK"<<std::endl;
    std::cout.flush();
    std::cin>>input;
    std::cout<<"END"<<std::endl;
}


require 'open3'

expected_string = "EXECUTE TASK"
Open3.popen2('~/Sandbox/a.out') { |stdin, stdout|
  found = false
  begin
    while(result = stdout.readline)
      puts result
      if(result.include?(expected_string))
        found = true
        break
      end
    end
  rescue
    raise "Exception caught while reading lines"
  end
  stdin.write('\n')
  stdin.close
}

【问题讨论】:

    标签: ruby iostream popen


    【解决方案1】:

    看起来像死锁:

    1. ruby 脚本正在调用IO::readlines,在读取整个流之前不会返回。
    2. C++ 程序在收到回车之前不会真正终止。

    您可能想要调用IO::readline,它会在收到每一行时返回它,或者重新排序两个脚本以避免死锁。

    【讨论】:

    • 那行得通。将在原始帖子中编辑解决方案。谢谢。
    【解决方案2】:

    您很可能只需要 stdout.flush 在您希望您的通讯员采取任何行动之后。

    因为#popen设置的管道不是tty,所以不会默认行缓冲。它会做块缓冲。您需要通过在“记录”边界上调用 #flush 来强制您的流以数据报方式运行。

    另外,请参阅 IO#sync= 了解自动刷新所有 I/O 的方法。

    【讨论】:

    • 我没有提到我在使用 stdout 和 stdin IO 对象之前已经尝试过刷新,但它仍然表现出相同的行为。另外值得一提的是,如果我的 C++ 程序只使用其中一个流而不是同时使用 cin 和 cout,那么排序就无关紧要了。
    • 流的 C++ 和 Ruby 端可能都需要刷新操作。
    • 所以我在 cout 之后将 std::cout.flush(); 添加到 C++ 中,并在 stdout.readlines 之后添加了 stdout.flush ,但仍然没有骰子。我会把上面的代码贴出来。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 2018-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    相关资源
    最近更新 更多