Проблема упорядочения при использовании Ruby popen2 для взаимодействия с Cost iostreams - PullRequest
1 голос
/ 25 мая 2011

Я использую popen2 Open3 для взаимодействия с iostreams простой программы на C ++. Насколько я понимаю, что std :: cin и std :: cout независимы, но порядок, в котором у меня есть вызовы чтения / записи объектов ввода-вывода моего блока popen2, кажется, имеет значение. Моя программа на 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 ​​будет зависать. Мое намерение состоит в том, чтобы условно записать \ n в stdin, если программа C ++ сначала записывает expected_string в стандартный формат, но я вынужден закрыть поток stdin, прежде чем смогу выполнить 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
}

Ответы [ 2 ]

1 голос
/ 25 мая 2011

Похоже на тупик:

  1. Сценарий ruby ​​вызывает IO::readlines, который не вернется, пока весь поток не будет прочитан.
  2. Программа C ++ фактически не завершает работу, пока не получит возврат каретки.

Возможно, вы захотите вызвать IO::readline, который будет возвращать каждую строку по мере ее поступления, или переупорядочить два сценария, чтобы не было тупиков.

0 голосов
/ 25 мая 2011

Весьма вероятно, что вам просто нужно stdout.flush после всего, что вы ожидаете от своего корреспондента.

Поскольку канал, настроенный с помощью #popen, не является tty, он по умолчанию не будет использовать буферизацию строки. Это сделает блок буферизации. Вам нужно будет заставить свой поток действовать дейтаграммы, вызвав #flush на границах «записи».

Также см. IO#sync=, чтобы узнать, как автоматически сбросить все данные ввода / вывода.

...