取消Swift未到达C任务的信号

gudnpqoy  于 2023-06-28  发布在  Swift
关注(0)|答案(1)|浏览(146)

我有一个Swift初始化器,用标准的argc/argv参数启动一个C任务,它工作得很好,但我想传递一个指向kill信号的指针(isCancelled),这样当我关闭父Swift程序时,它就可以做一些清理工作。在我这里的测试中,我在取消任务之前只等待10秒,我能够传递指针,但当我取消任务时,指针的值不会改变。下面是代码-打印显示isCancelled在取消后为true,但我的C任务(myClient)总是看到 *isCancelled的值为0:

init() {
        let myClientTask: Task = Task {
            let argc: CInt = 2
            var argv: [UnsafePointer<CChar>?] = [("IndigoPolarAlignAid" as NSString).utf8String,("2" as NSString).utf8String,nil]
            var isCancelled: Bool = Task.isCancelled
            _ = myClient(argc, &argv, &isCancelled)
        }
        let _: Task = Task {
            sleep(10) // Seconds
            print("Timesup!")
            myClientTask.cancel()
            print("SWClient: isCancelled is \(myClientTask.isCancelled)")
        }
    }
prdp8dxp

prdp8dxp1#

在示例中,isCancelled只是一个局部变量,它只被赋值一次。它与Task的isCancelled属性没有任何连接,只是在某个时候用它的值初始化。这里需要的是一个取消处理程序,它将在任务取消时运行。
如果你想传递一个你可以读的C指针,它应该沿着以下几行:

let myClientTask: Task = Task {
    let argc: CInt = 2
    var argv: [UnsafePointer<CChar>?] = [("IndigoPolarAlignAid" as NSString).utf8String,("2" as NSString).utf8String,nil]

    let isCancelled = UnsafeMutablePointer<Bool>.allocate(capacity: 1)
    isCancelled.initialize(to: Task.isCancelled)
    defer { isCancelled.deallocate() }

    await withTaskCancellationHandler {
        _ = myClient(argc, &argv, isCancelled)
    } onCancel: {
        isCancelled.pointee = true
    }
}

也就是说,这不是线程安全的(在没有锁的情况下通过指针在不同线程上进行阅读不是定义的行为)。传递原子类型而不是BOOL*会更好,但是使用什么类型有点取决于你的C代码,尽管我会检查Swift Atomics,它应该可以很好地与C互操作,而不必去pthreads。(我没有尝试过用这种方式在语言之间传递原子;其他人可能对此有更完整的答案。)
我通常建议不要这样做,而是创建另一个你可以在onCancel中调用的C函数,它将负责关闭。
此外,正如Sweeper指出的,您的sleep应该是:

try await Task.sleep(for: .seconds(10))

相关问题