双重fork和标准输入

4

我编写了这段代码来使我的进程在守护进程中运行。目标是即使关闭其父进程,该进程仍将继续运行。现在,我想能够在其标准输入(stdin)中输入一些内容。我该怎么做?下面是代码:

def daemonize(cmd, options = {})
  rd, wr = IO.pipe
  p1 = Process.fork {
    Process.setsid
    p2 = Process.fork {
      $0 =  cmd #Name of the command
      pidfile = File.new(options[:pid_file], 'w')
      pidfile.chmod( 0644 )
      pidfile.puts "#{Process.pid}"
      pidfile.close
      Dir.chdir(ENV["PWD"] = options[:working_dir].to_s) if options[:working_dir]
      File.umask 0000
      STDIN.reopen '/dev/null'
      STDOUT.reopen '/dev/null', 'a'
      STDERR.reopen STDOUT
      Signal.trap("USR1") do
        Console.show 'I just received a USR1', 'warning'
      end
      ::Kernel.exec(*Shellwords.shellwords(cmd)) #Executing the command in the parent process
      exit
    }
    raise 'Fork failed!' if p2 == -1
    Process.detach(p2) # divorce p2 from parent process (p1)
    rd.close
    wr.write p2
    wr.close
    exit
  }
  raise 'Fork failed!' if p1 == -1
  Process.detach(p1) # divorce p1 from parent process (shell)
  wr.close
  daemon_id = rd.read.to_i
  rd.close
  daemon_id
end

有没有一种方法可以重新打开类似于管道的stdin,而不是在/dev/null中,我能够在其中写入?
1个回答

2

那么使用先进先出(FIFO)队列如何呢?在Linux中,您可以使用mkfifo命令:

$ mkfifo /tmp/mypipe

然后您可以在该管道上重新打开STDIN:

STDIN.reopen '/tmp/mypipe'
# Do read-y things

任何其他内容都可以写入该管道:

$ echo "roflcopter" > /tmp/mypipe

允许Ruby进程读取数据。

(更新) 阻塞的注意事项

由于FIFO在没有读写时会阻塞(例如,除非有写入,否则读取将被阻塞,反之亦然),因此最好使用多个线程进行处理。一个线程应该负责读取数据,将其传递给队列,另一个线程应该处理该输入。以下是该情况的示例:

require 'thread'

input = Queue.new
threads = []

# Read from the fifo and add to an input queue (glorified array)
threads << Thread.new(input) do |ip|
  STDIN.reopen 'mypipe'
  loop do
    if line = STDIN.gets
      puts "Read: #{line}"
      ip.push line
    end
  end
end

# Handle the input passed by the reader thread
threads << Thread.new(input) do |ip|
  loop do
    puts "Ouput: #{ip.pop}"
  end
end

threads.map(&:join)

谢谢帮助。我做了这个,但我的代码卡在 STDIN.reopen '/tmp/mypipe' 上。你知道为什么吗? - Maxence Henneron
是的,使用FIFO的问题在于它们会阻塞,直到完成读/写操作。因此,在使用mkfifo之后,尝试将其作为流打开将会阻塞,直到有数据被写入。您可以在新线程中打开它以绕过此问题,请参见更新后的答案以获取基本示例。 - Jon Cairns

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接