1

Open3.capture3在我的 ruby​​ 代码中使用并开始注意到死锁。我做了一些研究,发现了这个关于 open3 如何导致死锁的很棒的博客。考虑到这一点,我想出了自己的 capture3 方法(仍在使用Open3.popen3)来替换我当前使用的方法(见下文)。但是我发现死锁似乎仍在发生,责任方是wait_thread.value获取Process::Status. 查看Open3源代码,我可以看到这个 wait_thread 只是Process::Waiter你从Process.detach调用中得到的。我想知道是什么导致了这种僵局?有什么方法可以检查这个线程是否死锁,杀死它并返回一个自定义Process::Status(我想返回一个Process::Status而不是仅仅保持内联的整数Open3.capture3

def capture3(cmd)
  out_buff = ''
  err_buff = ''
  chunk_size = 4096
  # Progressive timeout array
  sleeps = [[0.05]*20,[0.1]*5,[0.5]*3,1,2].flatten
  _in, out, err, wait_thread = Open3.popen3(cmd)
  _in.close
  open_pipes = [out, err]
  while !open_pipes.empty?
    timeout = sleeps.shift || timeout
    ready_pipes, *_ = IO.select(open_pipes, nil, nil, timeout)
    ready_pipes.each do |pipe|
      tmp = ''
      begin
        tmp << pipe.readpartial(chunk_size)
      rescue EOFError
        pipe.close
        open_pipes.delete(pipe)
      end
      out_buff << tmp if pipe == out
      err_buff << tmp if pipe == err
    end
  end
  [out_buff, err_buff, wait_thread.value]
end

注意我使用的 ruby​​ 版本是 2.2.5 并且在 Mac 上运行。

编辑:确切的错误No live threads left. Deadlock? (fatal)指向 wait_thread.value 调用的行号。我在另一个函数中调用 capture3 方法,在该函数中我像这样分叉进程

def fork_process(cmd, options={})
  pid = fork {
    Process.setproctitle(options[:process_name]) unless options[:process_name].nil?
    ENV.merge!(options[:environment])
    stdout, stderr, status = capture3(cmd)
    yield(stdout, stderr, status) if block_given?
  }
  Process.detach(pid)
end

完整的堆栈跟踪:

/home/myapp/utils.rb:769:in `value': No live threads left. Deadlock? (fatal)
        from /home/myapp/utils.rb:769:in `capture3'
        from /home/myapp/utils.rb:106:in `block in fork_process'
        from /home/myapp/utils.rb:104:in `fork'
        from /home/myapp/utils.rb:104:in `fork_process'
        from /home/myapp/server.rb:396:in `block in <class:MyServer>'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1611:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1611:in `block in compile!'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:975:in `[]'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:975:in `block (3 levels) in route!'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:994:in `route_eval'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:975:in `block (2 levels) in route!'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1015:in `block in process_route'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1013:in `catch'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1013:in `process_route'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:973:in `block in route!'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:972:in `each'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:972:in `route!'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1085:in `block in dispatch!'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1067:in `block in invoke'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1067:in `catch'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1067:in `invoke'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1082:in `dispatch!'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:907:in `block in call!'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1067:in `block in invoke'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1067:in `catch'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1067:in `invoke'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:907:in `call!'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:895:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/rack-protection-1.5.3/lib/rack/protection/xss_header.rb:18:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/rack-protection-1.5.3/lib/rack/protection/path_traversal.rb:16:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/rack-protection-1.5.3/lib/rack/protection/json_csrf.rb:18:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/rack-protection-1.5.3/lib/rack/protection/frame_options.rb:31:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/rack-1.6.5/lib/rack/nulllogger.rb:9:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/rack-1.6.5/lib/rack/head.rb:13:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/show_exceptions.rb:25:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:182:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:2013:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1487:in `block in call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1787:in `synchronize'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/sinatra-1.4.8/lib/sinatra/base.rb:1487:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/puma-3.8.2/lib/puma/configuration.rb:224:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/puma-3.8.2/lib/puma/server.rb:600:in `handle_request'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/puma-3.8.2/lib/puma/server.rb:435:in `process_client'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/puma-3.8.2/lib/puma/server.rb:299:in `block in run'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/puma-3.8.2/lib/puma/thread_pool.rb:120:in `call'
        from /Users/app/.rvm/gems/ruby-2.2.5/gems/puma-3.8.2/lib/puma/thread_pool.rb:120:in `block in spawn_thread'
4

0 回答 0