You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++程序调用ruby_init()后SIGINT信号处理异常问题

问题原因

Ruby解释器初始化(ruby_init())时会接管SIGINT等信号的处理逻辑,将其替换为Ruby内部的信号处理机制。但Ruby的信号处理依赖自身的VM调度——只有当Ruby VM有机会运行信号检查逻辑时,才会触发对应的trap代码。如果你的C++主循环没有主动触发Ruby的信号检查,SIGINT信号会被Ruby暂存,无法及时处理,直到ruby_finalize()恢复系统默认的信号处理。

你尝试的Signal.trap代码未生效,正是因为C++主循环没有给Ruby VM执行信号处理的机会,trap块根本没被调用。

解决办法

1. 在C++循环中触发Ruby信号检查

在C++的while (isOpen)循环内,定期调用Ruby的rb_thread_check_ints()函数,让Ruby VM检查并处理pending的信号:

#include <ruby.h>
#include <iostream>
#include <chrono>
#include <thread>

int main()
{
  bool isOpen = true;

  ruby_init();
  // 设置Ruby的SIGINT处理,加入退出逻辑
  rb_eval_string("Signal.trap('INT') { puts 'interrupt signal received'; exit }");

  while (isOpen) {
    // 你的业务代码
    std::cout << "Running..." << std::endl;
    
    // 定期检查Ruby信号,让trap有机会执行
    rb_thread_check_ints();
    
    // 可选:加小延迟避免CPU占用过高
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  ruby_finalize();
  return 0;
}

如果需要优雅退出而非直接终止,可以在Ruby的trap块中设置一个全局标志,再在C++循环中检测该标志来退出:

// Ruby侧设置标志
rb_eval_string("exit_flag = false; Signal.trap('INT') { puts 'interrupt received'; exit_flag = true }");

// C++循环中检测标志
while (isOpen) {
  VALUE exit_flag = rb_gv_get("exit_flag");
  if (RTEST(exit_flag)) {
    isOpen = false;
    break;
  }
  
  rb_thread_check_ints();
  // 业务代码...
}

2. 恢复C++的SIGINT信号处理(无需Ruby处理时)

如果不需要Ruby处理SIGINT,可以在ruby_init()之后重新注册C++的信号处理函数,覆盖Ruby的接管:

#include <ruby.h>
#include <iostream>
#include <csignal>
#include <chrono>
#include <thread>

volatile sig_atomic_t stop = 0;

void handle_sigint(int sig) {
  stop = 1;
}

int main()
{
  signal(SIGINT, handle_sigint);
  bool isOpen = true;

  ruby_init();
  // 重新注册SIGINT处理,覆盖Ruby的设置
  signal(SIGINT, handle_sigint);

  while (isOpen && !stop) {
    // 你的业务代码
    std::cout << "Running..." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  ruby_finalize();
  return 0;
}

注意:这种方式可能和Ruby内部的信号处理逻辑冲突,仅适合不需要Ruby参与信号处理的场景。

3. 用Ruby事件循环主导程序运行

如果业务逻辑以Ruby为主,可以让Ruby的事件循环主导程序,这样Ruby会自动处理信号:

#include <ruby.h>

int main()
{
  ruby_init();
  
  rb_eval_string(R"(
    Signal.trap('INT') { puts 'interrupt received'; exit }
    loop do
      puts 'Ruby running...'
      sleep 0.1
    end
  )");
  
  rb_main_loop();
  ruby_finalize();
  return 0;
}

内容的提问来源于stack exchange,提问作者Gabriel Martins

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:32:54