How to terminate all threads reading from Pipe (NSPipe) related to Process (NSTask)?

你。 提交于 2020-01-04 06:36:09

问题


I am writing a MacOS/Cocoa app that monitors a remote log file using a common recipe that launches a Process (formerly NSTask) instance on a background thread and reads stdout of the process via a Pipe (formally a NSPipe) as listed below:

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
   }
}

Everything works just dandy, but when the process quits (killed via process.terminate) I notice (via Xcode's Debug Navigator and the Console app) that there are multiple threads consuming 180% or more of the CPU!?!

Where is this CPU leak coming from?

I threw in outHandle.closeFile() (see code marked XXX above) and that reduced the CPU usage down to just a few percent but the threads still existed! What am I doing wrong or how do a make sure all the related threads terminate (I prefer graceful terminations i.e., threads body finish executing)!?

Some one posted a similar question almost 5 years ago!

UPDATE:

The documentation for NSFileHandle's readabilityHandler says:

To stop reading the file or socket, set the value of this property to nil. Doing so cancels the dispatch source and cleans up the file handle’s structures appropriately.

so setting outHandle.readabilityHandler = nil seems to solve the problem too.

Even though I have seemingly solved the problem, I really don't understand where this massive CPU leak comes from -- very mysterious.

来源:https://stackoverflow.com/questions/44833266/how-to-terminate-all-threads-reading-from-pipe-nspipe-related-to-process-nsta

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!