- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个用 C++ 编写的旧应用程序,我正在将其移植到 Ruby。
代码的一部分使用 execl()
,以便用其自身的[n更新]副本替换进程,同时维护打开的文件描述符(此应用程序是一项网络服务)。
if ( execl( "./my-app", "-restart", fd.c_str(), NULL ) < 0 ) {
没过多久就发现 Ruby 没有 execl()
等效项,但您可以使用 Process::spawn
和 :close_others
选项部分伪造它。或者,至少我应该能够根据documentation :
file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not :close_others => true : don't inherit
因此,在我看来,以下内容应该生成一个新进程,该进程可以访问父进程的所有打开文件描述符:
server_fd = @server.to_i
env = {
"APP_REBOOT" => "true",
"APP_SERVER_FD" => server_fd.to_s,
}
command = "ruby my-app.rb"
options = {
:in => :in,
:out => :out,
:err => :err,
:close_others => false,
}
pid = Process.spawn env, command, options
Process.detach pid
这将允许子进程访问描述符...但是我无法弄清楚如何在不关闭所有描述符的情况下退出父进程。换句话说,如果我导致父级在代码末尾退出
:
server_fd = @server.to_i
env = {
"APP_REBOOT" => "true",
"APP_SERVER_FD" => server_fd.to_s,
}
command = "ruby my-app.rb"
options = {
:in => :in,
:out => :out,
:err => :err,
:close_others => false,
}
pid = Process.spawn env, command, options
Process.detach pid
exit # ADDED THIS LINE
然后描述符也对子进程关闭。
我感觉这更多是我的流程管理方法的问题,而不是 Ruby 特有的问题,但我不明白我做错了什么。
<小时/>$ ruby -v
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]
<小时/>
编辑1就在我调用 Process.spawn(或 @mata 指出的 Process.exec)之前,我有一个诊断输出:
system 'lsof -c ruby'
在我的 recover_from_reboot
方法中再次调用该函数。这是重启前输出的尾部,您可以在最后两行看到监听的服务器端口和连接的客户端:
ruby 8957 chris 0u CHR 136,1 0t0 4 /dev/pts/1
ruby 8957 chris 1u CHR 136,1 0t0 4 /dev/pts/1
ruby 8957 chris 2u CHR 136,1 0t0 4 /dev/pts/1
ruby 8957 chris 3r FIFO 0,8 0t0 12213372 pipe
ruby 8957 chris 4w FIFO 0,8 0t0 12213372 pipe
ruby 8957 chris 5r FIFO 0,8 0t0 12213373 pipe
ruby 8957 chris 6w FIFO 0,8 0t0 12213373 pipe
ruby 8957 chris 7u IPv4 12213374 0t0 TCP localhost.localdomain:boks-servc (LISTEN)
ruby 8957 chris 8u IPv4 12213423 0t0 TCP localhost.localdomain:boks-servc->localhost.localdomain:45249 (ESTABLISHED)
这是我在重新启动后看到的内容:
ruby 8957 chris 3r FIFO 0,8 0t0 12203947 pipe
ruby 8957 chris 4w FIFO 0,8 0t0 12203947 pipe
ruby 8957 chris 5r FIFO 0,8 0t0 12203948 pipe
ruby 8957 chris 6w FIFO 0,8 0t0 12203948 pipe
这又是我尝试 spawn
还是 exec
的问题。
编辑2根据我的诊断输出,我看到服务器保持绑定(bind)到 fd 7,客户端保持绑定(bind)到 8。通过添加
7 => 7,
8 => 8,
对于我的options
数组,我能够使用exec
在重新启动时成功地保留这些套接字。我可以手动将服务器和 [client1, client2,...]
fd
添加到选项哈希中,但是当 :close_others
应该为我做繁重的工作时,这看起来很脏。
最佳答案
这当然不是我正在寻找的解决方案,但在没有任何有关 :close_options
哈希和 Process.spawn
或 Process.exec
的情况下,我最终手动将我关心的所有文件描述符添加到 option
数组中,这达到了目的:
server_fd = self.server.to_i
client_fds = self.clients.map { |c| c.get_fd }
env = {
"APP_REBOOT" => "true",
"APP_SERVER_FD" => server_fd.to_s,
"APP_CLIENT_FDS" => Marshal.dump(client_fds),
}
options = {
:in => :in,
:out => :out,
:err => :err,
:close_others => false,
}
# Add the server socket to the options Hash.
options[server_fd] = server_fd
# Add all the client sockets to the options Hash.
@clients.each { |c| options[c.get_fd] = c.get_fd }
# Begin anew.
Process.exec env, App.binary.to_s, options
我会暂时不接受这个答案,以防有人过来澄清事实。
关于ruby - 如何在 Ruby 中模仿 execl(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23176959/
我是一名优秀的程序员,十分优秀!