GCD and Process


(Mr Bee) #1

Hi all,
I'm currently still learning Swift 3. Now I'm playing around with GCD (grand central dispatch). I'd like to start an external process using Process from an asynced thread, and create another thread to stop that external process after some times. Here's what I do…
import Foundationimport Dispatch
extension Process { func execute(command: String, currentDir: String = "~", arguments: [String] = [], input: String = "") -> String { if !input.isEmpty { let pipeIn = Pipe() self.standardInput = pipeIn // multiple inputs are separated by newline if let input = input.data(using: String.Encoding.utf8) { pipeIn.fileHandleForWriting.write(input) } } let pipeOut = Pipe() self.standardOutput = pipeOut self.arguments = arguments self.launchPath = command self.currentDirectoryPath = currentDir self.launch() let output = pipeOut.fileHandleForReading.readDataToEndOfFile() self.waitUntilExit() return String(data: output, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))! }}
//print(Process().execute(command: "/bin/ls", arguments: ["-l"]))
var cmd = Process()
print("Starting...")
DispatchQueue.global(qos: .default).async { print("Executing...") let s = cmd.execute(command: "/bin/ls", arguments: ["-l"]) print(s)}
DispatchQueue.global(qos: .default).asyncAfter(deadline: DispatchTime.now() + .seconds(5)) { if cmd.isRunning { print("Terminating...") cmd.terminate() }}
print("Done.")
The code doesn't work as expected. The execute() function itself works fine (uncomment the call in the middle of the code), but I don't know why it doesn't work if it's called from within DispatchQueue closure. Even if I call a much more simple function —like a for loop— it doesn't work consistenly, sometimes the loop is completed, but other times it's not.
Google didn't really help me because this topic is pretty rare I suppose. Could anyone enlight me, how to make the code works as I expected? What did I do wrong?
Thank you.
Regards,

–Mr Bee


(Shawn Erickson) #2

It looks like you aren't keeping your app alive to allow the secondary
queue to reliably execute the closures you queue with it. It isn't really
clear what you want to attempt so it hard to suggest the correct way to do
things.

-Shawn

···

On Thu, Jan 5, 2017 at 11:39 PM Mr Bee via swift-users < swift-users@swift.org> wrote:

Hi all,

I'm currently still learning Swift 3. Now I'm playing around with GCD
(grand central dispatch). I'd like to start an external process using
Process from an asynced thread, and create another thread to stop that
external process after some times. Here's what I do…

import Foundation
import Dispatch

extension Process {
  func execute(command: String, currentDir: String = "~", arguments: [
String] = [], input: String = "") -> String {
    if !input.isEmpty {
      let pipeIn = Pipe()
      self.standardInput = pipeIn
      *// multiple inputs are separated by newline*
      if let input = input.data(using: String.Encoding.utf8) {
        pipeIn.fileHandleForWriting.write(input)
      }
    }

    let pipeOut = Pipe()
    self.standardOutput = pipeOut

    self.arguments = arguments
    self.launchPath = command
    self.currentDirectoryPath = currentDir

    self.launch()
    let output = pipeOut.fileHandleForReading.readDataToEndOfFile()
    self.waitUntilExit()

    return String(data: output, encoding: String.Encoding(rawValue: String
.Encoding.utf8.rawValue))!
  }
}

*//print(Process().execute(command: "/bin/ls", arguments: ["-l"]))*

var cmd = Process()

print("Starting...")

DispatchQueue.global(qos: .default).async {
  print("Executing...")
  let s = cmd.execute(command: "/bin/ls", arguments: ["-l"])
  print(s)
}

DispatchQueue.global(qos: .default).asyncAfter(deadline: DispatchTime.now()
+ .seconds(5)) {
  if cmd.isRunning {
    print("Terminating...")
    cmd.terminate()
  }
}

print("Done.")

The code doesn't work as expected. The execute() function itself works
fine (uncomment the call in the middle of the code), but I don't know why
it doesn't work if it's called from within DispatchQueue closure. Even if
I call a much more simple function —like a for loop— it doesn't work
consistenly, sometimes the loop is completed, but other times it's not.

Google didn't really help me because this topic is pretty rare I suppose.
Could anyone enlight me, how to make the code works as I expected? What did
I do wrong?

Thank you.

Regards,

–Mr Bee

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Mr Bee) #3

How to make my app alive to make the second queue finish its job? What I want is:
- start program- start an external process from a thread (asynchronously)- start another thread after 5 seconds to terminate the process from the other thread- end program
That's all.
–Mr Bee

    Pada Jumat, 6 Januari 2017 14:49, Shawn Erickson <shawnce@gmail.com> menulis:

It looks like you aren't keeping your app alive to allow the secondary queue to reliably execute the closures you queue with it. It isn't really clear what you want to attempt so it hard to suggest the correct way to do things.

-Shawn

···

On Thu, Jan 5, 2017 at 11:39 PM Mr Bee via swift-users <swift-users@swift.org> wrote:

Hi all,
I'm currently still learning Swift 3. Now I'm playing around with GCD (grand central dispatch). I'd like to start an external process using Process from an asynced thread, and create another thread to stop that external process after some times. Here's what I do…
import Foundationimport Dispatch
extension Process { func execute(command: String, currentDir: String = "~", arguments: [String] = [], input: String = "") -> String { if !input.isEmpty { let pipeIn = Pipe() self.standardInput = pipeIn // multiple inputs are separated by newline if let input = input.data(using: String.Encoding.utf8) { pipeIn.fileHandleForWriting.write(input) } } let pipeOut = Pipe() self.standardOutput = pipeOut self.arguments = arguments self.launchPath = command self.currentDirectoryPath = currentDir self.launch() let output = pipeOut.fileHandleForReading.readDataToEndOfFile() self.waitUntilExit() return String(data: output, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))! }}
//print(Process().execute(command: "/bin/ls", arguments: ["-l"]))
var cmd = Process()
print("Starting...")
DispatchQueue.global(qos: .default).async { print("Executing...") let s = cmd.execute(command: "/bin/ls", arguments: ["-l"]) print(s)}
DispatchQueue.global(qos: .default).asyncAfter(deadline: DispatchTime.now() + .seconds(5)) { if cmd.isRunning { print("Terminating...") cmd.terminate() }}
print("Done.")
The code doesn't work as expected. The execute() function itself works fine (uncomment the call in the middle of the code), but I don't know why it doesn't work if it's called from within DispatchQueue closure. Even if I call a much more simple function —like a for loop— it doesn't work consistenly, sometimes the loop is completed, but other times it's not.
Google didn't really help me because this topic is pretty rare I suppose. Could anyone enlight me, how to make the code works as I expected? What did I do wrong?
Thank you.
Regards,

–Mr Bee
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Quinn “The Eskimo!”) #4

The standard approach here is to park the main thread [1] in `dispatchMain()`. Then, when all your work is done, exit the process explicitly by calling `exit(_:)`.

Share and Enjoy

···

On 6 Jan 2017, at 07:53, Mr Bee via swift-users <swift-users@swift.org> wrote:

How to make my app alive to make the second queue finish its job?

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

[1] This doesn’t actually park the thread (at least on Darwin platforms) but instead does the rather neat trick of terminating the main thread while leaving the process alive (-:


(Mr Bee) #5

[1] This doesn’t actually park the thread (at least on Darwin platforms) but instead does the rather neat trick of terminating the main thread while leaving the process alive (-:

How to do such a trick? Do you have any refferences that discuss further about this? I'm still a newbie with both Swift and GCD. There are still many things I have to read and understand.
Thank you.
–Mr Bee

    Pada Jumat, 6 Januari 2017 15:35, "Quinn "The Eskimo!" via swift-users" <swift-users@swift.org> menulis:

···

On 6 Jan 2017, at 07:53, Mr Bee via swift-users <swift-users@swift.org> wrote:

How to make my app alive to make the second queue finish its job?

The standard approach here is to park the main thread [1] in `dispatchMain()`. Then, when all your work is done, exit the process explicitly by calling `exit(_:)`.

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

[1] This doesn’t actually park the thread (at least on Darwin platforms) but instead does the rather neat trick of terminating the main thread while leaving the process alive (-:

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Quinn “The Eskimo!”) #6

By calling `dispatchMain()` or one of the various functions that calls `dispatchMain()`. There’s no lower-level interface to this.

Share and Enjoy

···

On 9 Jan 2017, at 05:56, Mr Bee <pak.lebah@yahoo.com> wrote:

How to do such a trick?

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware