捕获SIGINT和清除的正确方法?

时间:2019-03-01 19:10:36

标签: crystal-lang

编写一个cli工具,在启动时打开OS X Web代理,在关机时我想再次将其关闭。捕获SIGINT并执行应用清理的正确方法是什么?尝试以下操作,它跟踪消息,但不运行系统命令或退出:

Signal::INT.trap do
  puts "trap"
  fork do
    system "networksetup -setwebproxystate Wi-Fi off"
  end
  exit
end

此代码确实退出,但给出了“无效的内存访问”错误

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的完整“应用程序”,对我来说,这将正确打开和关闭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

2 个答案:

答案 0 :(得分:4)

您可以使用Fibers吗?

docker run --rm --volumes-from my-mongo-container -v $(pwd):/out ubuntu tar cvf /out/mongo-data-db.tar

答案 1 :(得分:2)

恕我直言,麻烦来自Crystal-lang的fork,它具有一些奇怪的语义。

当您尝试启动工作流程来运行system调用时,Crystal也复制了loop ...

执行exit时,第一个循环退出,而不是分叉的循环。

要验证这一点,您可以像这样在sleepfork块中写入一些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已使用纤维回答了替代方法。

进一步阅读:Process.fork has dangerous semantics