我正在编写一个MacOS / Cocoa应用程序,该应用程序使用在后台线程上启动Process
(以前称为NSTask
)实例的通用配方来监视远程日志文件并读取stdout
该流程通过Pipe
(正式为NSPipe
)列出,如下所示:
class LogTail {
var process : Process? = nil
func dolog() {
//
// Run ssh fred@foo.org /usr/bin/tail -f /var/log.system.log
// on a background thread and monitor it's stdout.
//
let processQueue = DispatchQueue.global(qos: .background)
processQueue.async {
//
// Create process and associated command.
//
self.process = Process()
process.launchPath = "/usr/bin/ssh"
process.arguments = ["fred@foo.org",
"/usr/bin/tail", "-f",
"/var/log.system.log"]
process.environment = [ ... ]
//
// Create pipe to read stdout of command as data is available
//
let pipe = Pipe()
process.standardOutput = pipe
let outHandle = pipe.fileHandleForReading
outHandle.readabilityHandler = { pipe in
if let string = String(data: pipe.availableData,
encoding: .utf8) {
// write string to NSTextView on main thread
}
}
//
// Launch process and block background thread
// until process complete.
//
process.launch()
process.waitUntilExit()
//
// What do I do here to make sure all related
// threads terminate?
//
outHandle.closeFile() // XXX
outHandle.readabilityHandler = nil // XXX
}
}
一切都很有效,但当进程退出(通过process.terminate
杀死)时,我注意到(通过Xcode的Debug Navigator和Console应用程序)有多个线程消耗了180%或更多的线程中央处理器!?!
这个CPU泄漏来自哪里?
我投入outHandle.closeFile()
(参见上面标记为XXX的代码)并将CPU使用率降低到几个百分点,但线程仍然存在!我做错了什么或如何确保所有相关的线程终止(我更喜欢优雅的终止,即线程主体完成执行)!?
有人在差不多5年前发布了similar question!
更新
NSFileHandle's readabilityHandler
的文档说:
要停止读取文件或套接字,请将此属性的值设置为 零。这样做会取消调度源并清理文件 妥善处理结构。
所以设置outHandle.readabilityHandler = nil
似乎也解决了这个问题。
即使我似乎解决了这个问题,但我真的不明白这个巨大的CPU漏洞来自哪里 - 非常神秘。