【问题标题】:Double fork and stdin双叉和标准输入
【发布时间】:2013-08-12 11:46:39
【问题描述】:

我编写这段代码是为了在守护进程中运行我的进程。目标是即使我关闭它的父进程也使这个进程运行。现在,我希望能够在其标准输入中写一些东西。我该怎么办 ?这是代码。

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

有没有办法以管道之类的方式重新打开标准输入,而不是 /dev/null 我可以在其中写入?

【问题讨论】:

    标签: ruby linux unix process


    【解决方案1】:

    fifo 怎么样?在linux中,可以使用mkfifo命令:

    $ mkfifo /tmp/mypipe
    

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

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

    其他任何东西都可以写入该管道:

    $ echo "roflcopter" > /tmp/mypipe
    

    允许 ruby​​ 进程读取该数据。

    (更新)关于阻塞的警告

    由于 fifos 会阻塞直到有读取和写入(例如,除非有写入,否则读取会被阻塞,反之亦然),因此最好使用多个线程来处理。一个线程应该进行读取,将数据传递给队列,另一个线程应该处理该输入。下面是这种情况的一个例子:

    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' 上。你知道为什么吗?
    • 是的,fifos 的问题是它们会阻塞直到发生完整的读/写。因此,在使用mkfifo 之后,尝试将其作为流打开将阻塞,直到写入某些内容。您可以在新线程中打开它来解决这个问题,请参阅更新的答案以获取基本示例。
    猜你喜欢
    • 2010-10-29
    • 2013-06-13
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    • 2021-10-20
    • 2010-12-01
    • 1970-01-01
    相关资源
    最近更新 更多