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

如何在Swift Package Manager构建的macOS CLI中捕获SIGINT与SIGTERM信号

在Swift PM的macOS CLI中捕获退出信号以清理资源

我正在使用Swift Package Manager开发一款面向macOS的CLI(可执行产品)。我的worker进程会处理数据并将输出写入文件,需要捕获SIGINT、SIGTERM或任何表明命令即将退出的信号,以便通知worker进行资源清理。请问如何在Swift Package Target中实现该功能?

初始代码如下:

@main
enum CLI {
    static func main() async throws {
        let worker = Worker()

        await worker.process()
    }
}

实现方案

在Swift中可以通过GCD的DispatchSourceSignal来捕获POSIX信号,这种方式比传统的signal()函数更安全,适配异步代码环境。下面是具体实现步骤:

1. 给Worker添加可中断逻辑

让Worker支持接收中断通知,利用Swift Task的取消机制触发资源清理:

class Worker {
    private var processingTask: Task<Void, Error>?
    
    func process() async throws {
        processingTask = Task {
            // 模拟长期运行的数据处理、文件写入逻辑
            while !Task.isCancelled {
                print("正在处理数据...")
                try await Task.sleep(nanoseconds: 1_000_000_000)
            }
            // 收到中断信号后执行清理
            print("开始清理资源:关闭文件句柄、保存临时数据...")
            // 这里添加实际清理代码,比如关闭FileHandle、删除临时文件等
        }
        
        try await processingTask?.value
    }
    
    func interrupt() {
        processingTask?.cancel()
    }
}

2. 在CLI主逻辑中设置信号捕获

在main函数里创建信号源,监听目标信号并触发Worker的清理流程:

@main
enum CLI {
    static func main() async throws {
        let worker = Worker()
        
        // 注册信号监听
        setupSignalHandling(for: [SIGINT, SIGTERM]) {
            print("\n收到退出信号,准备清理...")
            worker.interrupt()
        }
        
        try await worker.process()
        print("程序正常退出")
    }
    
    private static func setupSignalHandling(for signals: [Int32], handler: @escaping () -> Void) {
        for signal in signals {
            let source = DispatchSource.makeSignalSource(signal: signal, queue: .main)
            source.setEventHandler(handler: handler)
            source.resume()
            // 绑定信号源引用,防止被ARC释放导致监听失效
            objc_setAssociatedObject(self, "\(signal)", source, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        // 忽略系统默认信号处理,避免进程直接被终止
        signal(SIGINT, SIG_IGN)
        signal(SIGTERM, SIG_IGN)
    }
}

关键说明

  • DispatchSourceSignal优势:GCD提供的线程安全信号监听方式,适配Swift异步代码场景,避免传统signal()的线程安全问题。
  • Task取消机制:通过Task.isCancelled检测中断信号,让Worker优雅停止处理流程并执行资源清理。
  • 信号源引用保留:必须通过关联对象或全局变量保留信号源实例,否则会被自动释放导致监听失效。
  • 扩展信号支持:如果需要监听其他退出信号(如SIGHUP),直接将信号值添加到signals数组即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 05:31:11