如何在 Objective-C 函数中捕获 Ctrl-C 信号?

How to catch Ctrl-C signal inside an Objective-C function?

我的程序有一个主要功能,将执行一系列测试,其中将包括一些需要在用户 Ctrl-C 时终止的进程。

以下代码是正确的工作流程

- (void)run {
   [process1 start];
   [process2 start];
   Running...
   [process1 stop];
   [process2 stop];
}

但是用户可能会使用 Ctrl-C 来停止我的程序,我不想离开 process1 和 process2 运行 因为它们很危险。如何正确阻止它们? Kill 命令无法使用,因为我不知道动态进程名称,唯一的方法是在这两个 ObjC 对象上调用 stop

从技术上讲,在您的 Objective-C 方法中您无法捕获 SIGINT 信号(由用户在按下 CTRL-C 时生成)- 您的程序会 中断 . 此时的流程控制由内核处理。在执行 objective-c run 方法期间有效的 cpu 寄存器状态不可避免地会丢失。因此你不能继续执行你的run方法了。

您可以做的是使用 C API.

注册自定义 SIGINT 处理程序
#import <signal.h>
void sigHandler(int sig) {
    //as noted by @bbum list of functions with guaranteed behavior in sighandler is very limited
    //obj-c runtime is definitely NOT on the list
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
       [process1 stop];
       [process2 stop];
    });
    //give extra time for the async part to run
    usleep(50);
}

int main(int argc, const char * argv[]) {
    signal(SIGINT, sigHandler);
    @autoreleasepool {
        //your normal program launch goes here  
    }
    return 0;
}

如果你有一个控制台应用程序,你可以考虑路由 here 所以基本上禁用 CTRL-C 触发 SIGINT 并自己异步处理 CTRL-C 的键盘读取。主要的缺点是如果你的程序会遇到无限循环,它不能用 CTRL-C 中断。因此,为了尽量减少这种影响,您可以在 run 方法的开头设置这种特殊的终端模式,并在完成后恢复它。