捕获 SIGINT 和清理的正确方法?
Correct way to catch SIGINT and cleanup?
编写一个 cli 工具,在启动时打开 OS X 网络代理,在关闭时我想再次将其关闭。捕获 SIGINT 并执行应用程序清理的正确方法是什么?尝试了以下并跟踪了消息,但没有 运行 系统命令或退出:
Signal::INT.trap do
puts "trap"
fork do
system "networksetup -setwebproxystate Wi-Fi off"
end
exit
end
此代码确实退出但给出了 'Invalid memory access' 错误
at_exit do
fork do
system "networksetup -setwebproxystate Wi-Fi off"
end
end
LibC.signal Signal::INT.value, ->(s : Int32) { exit }
Invalid memory access (signal 10) at address 0x10d3a8e00
[0x10d029b4b] *CallStack::print_backtrace:Int32 +107
[0x10d0100d5] __crystal_sigfault_handler +181
[0x7fff6c5b3b3d] _sigtramp +29
更新
这是使用 Signal::INT.trap
的完整 'app',对我来说 运行ning 将正确打开和关闭 OS X 代理设置,但循环将继续运行中断信号后
fork do
system "networksetup -setwebproxy Wi-Fi 127.0.0.1 4242"
end
Signal::INT.trap do
puts "trap"
fork do
system "networksetup -setwebproxystate Wi-Fi off"
end
exit
end
loop do
sleep 1
puts "foo"
end
您可以使用 Fibers?
spawn do
system "networksetup -setwebproxy Wi-Fi 127.0.0.1 4242"
end
sleep 0.1
Signal::INT.trap do
puts "trap"
spawn do
system "networksetup -setwebproxystate Wi-Fi off"
end
sleep 0.1
exit
end
loop do
sleep 1
puts "foo"
end
恕我直言,麻烦来自 crystal-lang 的 fork
,它有一些奇怪的语义。
当您尝试启动工作进程以 运行 system
调用时,crystal 也复制了 loop
...
并且当exit
执行时,第一个循环退出,而不是分叉的循环。
要验证这一点,您可以像这样将一些 sleep
写入 fork
和 INT.trap
块:
fork do
system "echo \"start\""
end
Signal::INT.trap do
puts "trap"
fork do
system "echo \"off\""
sleep 15
end
sleep 20
exit
end
loop do
sleep 1
puts "foo"
end
然后尝试连续观察ps
命令的结果。
@Sergey Fedorov 使用光纤回答了替代方法。
编写一个 cli 工具,在启动时打开 OS X 网络代理,在关闭时我想再次将其关闭。捕获 SIGINT 并执行应用程序清理的正确方法是什么?尝试了以下并跟踪了消息,但没有 运行 系统命令或退出:
Signal::INT.trap do
puts "trap"
fork do
system "networksetup -setwebproxystate Wi-Fi off"
end
exit
end
此代码确实退出但给出了 'Invalid memory access' 错误
at_exit do
fork do
system "networksetup -setwebproxystate Wi-Fi off"
end
end
LibC.signal Signal::INT.value, ->(s : Int32) { exit }
Invalid memory access (signal 10) at address 0x10d3a8e00
[0x10d029b4b] *CallStack::print_backtrace:Int32 +107
[0x10d0100d5] __crystal_sigfault_handler +181
[0x7fff6c5b3b3d] _sigtramp +29
更新
这是使用 Signal::INT.trap
的完整 'app',对我来说 运行ning 将正确打开和关闭 OS X 代理设置,但循环将继续运行中断信号后
fork do
system "networksetup -setwebproxy Wi-Fi 127.0.0.1 4242"
end
Signal::INT.trap do
puts "trap"
fork do
system "networksetup -setwebproxystate Wi-Fi off"
end
exit
end
loop do
sleep 1
puts "foo"
end
您可以使用 Fibers?
spawn do
system "networksetup -setwebproxy Wi-Fi 127.0.0.1 4242"
end
sleep 0.1
Signal::INT.trap do
puts "trap"
spawn do
system "networksetup -setwebproxystate Wi-Fi off"
end
sleep 0.1
exit
end
loop do
sleep 1
puts "foo"
end
恕我直言,麻烦来自 crystal-lang 的 fork
,它有一些奇怪的语义。
当您尝试启动工作进程以 运行 system
调用时,crystal 也复制了 loop
...
并且当exit
执行时,第一个循环退出,而不是分叉的循环。
要验证这一点,您可以像这样将一些 sleep
写入 fork
和 INT.trap
块:
fork do
system "echo \"start\""
end
Signal::INT.trap do
puts "trap"
fork do
system "echo \"off\""
sleep 15
end
sleep 20
exit
end
loop do
sleep 1
puts "foo"
end
然后尝试连续观察ps
命令的结果。
@Sergey Fedorov 使用光纤回答了替代方法。