Ruby IO.popen с "-", что происходит под капотом? - PullRequest
2 голосов
/ 10 апреля 2011

Я пытаюсь понять IO.popen, когда его команда "-" запускает новый интерпретатор Ruby.

По этому предмету не так много материала, и я медленно прохожу через него,главным образом из-за того, что я пишу только для развлечения.

Насколько я понял, когда вызывается IO.popen("-", "w+") {|f| ...} - это с блоком - этот блок будет запускаться обоими родителеми дочерний процесс.Разница в том, что в результате родительский процесс получит объект ввода-вывода, а дочерний - только ноль.Это просто, мне нужно проверить |f| в блоке, и когда это Nil, выполнение находится в дочернем процессе, когда это не nil, выполнение находится в родительском.Поэтому я должен написать код для родителя и потомка, разделенный if.

На этот раз мне помогает понять проблему: блок является частью команды IO.popen .

У меня есть этот код:

pipe = IO.popen("-","w+")
# puts "This line will break functionality if uncommented"
  if pipe != nil then
    pipe.puts "PID: #{Process.pid}"
    $stderr.puts "Parent from child: #{pipe.gets.chomp}"
  else
    $stderr.puts "Child PID: #{Process.pid} and Parent #{gets.chomp}"
    puts "M'kay"
  end

Вопросы:

  • Что решает, какой процесс запускается первым?Если они добавят файл, будет ли он уязвим к состоянию гонки?
  • Почему 2-я строка нарушает код?Команда pipe = IO.popen... не должна относиться к блоку if..else..end, но они есть.Для меня pipe - это дескриптор файла (как в старом Turbo Pascal), который сначала определяется где-то, а затем обрабатывается в другом месте.

1 Ответ

2 голосов
/ 10 апреля 2011

Никто не решает, какой процесс запускается первым.Дочерний процесс может запускаться первым - или родительский процесс может запускаться первым - ОС может планировать их в любом случае.

Это означает, что родительский процесс может завершиться до завершения дочернего процесса.Когда родительский процесс завершается, канал к нему закрывается, и когда дочерний процесс пишет в него, он получает исключение.Вот что происходит в вашем коде.

Почему это не происходит без закомментированной строки?Когда вы вызываете gets в родительском процессе, он ждет, пока дочерний процесс не записывает строку в канал.Это означает, что родитель не завершит работу, пока ребенок не напишет строку в канал, и это пренебрегает проблемой.Однако при печати двух строк вероятность того, что родительский процесс завершится до того, как дочерний процесс выполнит второе puts "M'kay" увеличение.

Попробуйте следующий код:

pipe = IO.popen("-","w+")
puts "This line will not break functionality"
puts "This line will not break functionality"
puts "This line will not break functionality"
  if pipe != nil then
    pipe.puts "PID: #{Process.pid}"
    while line = pipe.gets
      $stderr.puts "Parent from child: #{line.chomp}"
    end
  else
    $stderr.puts "Child PID: #{Process.pid} and Parent #{gets.chomp}"
    puts "M'kay"
  end

Он ждет, пока дочерний объект не закроет канал (тогда pipe.gets вернет nil), что произойдет, затем он завершится, и он гарантирует, что больше не будет пытаться писать туда.

...