Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > Monitoring an NSTask subprocess

Monitoring an NSTask subprocess
Thread Tools
wataru
Addicted to MacNN
Join Date: Oct 2001
Location: Yokohama, Japan
Status: Offline
Reply With Quote
Aug 28, 2005, 04:57 PM
 
For a number of reasons, I need to run an untrustworthy program as an NSTask. I say "untrustworthy" because this program can sometimes crash and spit garbage to standard out. I need to save standard out to a file; there is no way around that.

What I've done in other, non-Cocoa implementations of my app is launch the bad program as a background task, and then poll it like so (pseudocode):
Code:
while process is running if log file is larger than x, do blah blah else sleep for n seconds end while
This isn't very good in Cocoa because the C sleep() call hangs the whole app beachball-style. Not sleeping means pegging the processor until the NSTask finishes.

So how can I monitor things like this cleanly? I've looked at run loops and whatnot, but I don't really understand them.
     
PBG4 User
Senior User
Join Date: Feb 2001
Location: Deer Crossing, CT
Status: Offline
Reply With Quote
Aug 30, 2005, 10:18 AM
 
You could spawn a thread. I use the sleep() function in a thread in my Musical Scales program. The source is available along with the program if you want to poke around in there.

If the log file is pushed through standard out you can use an NSPipe object to redirect standard out. Otherwise you could use some kind of file object (NSFileHandler?) to monitor the log file. You would still need to use threading to keep this sort of monitoring from hanging up your program though.

I thought spawning a new thread was daunting at first, but it turned out to be quite easy.
20" iMac G5! :D AND MacBook 1.83GHz!
Canon Digital Rebel Kit + 75 - 300mm lens. Yum Yum! :D
Check out my OS X Musical Scales program
     
__^^__
Forum Regular
Join Date: Feb 2005
Status: Offline
Reply With Quote
Aug 30, 2005, 05:16 PM
 
Code:
while process is running if log file is larger than x, do blah blah else sleep for n seconds end while
Also, does the program flush it's output sufficiently? If not, you may not see all output.
     
arcticmac
Dedicated MacNNer
Join Date: Apr 2004
Status: Offline
Reply With Quote
Sep 4, 2005, 10:01 PM
 
http://www.cocoadevcentral.com/articles/000031.php

that article has some good stuff... poke around.
     
Brass
Professional Poster
Join Date: Nov 2000
Location: Tasmania, Australia
Status: Offline
Reply With Quote
Sep 5, 2005, 06:23 PM
 
Check the Apple documentation for the NSTask class. There is no need to do ANY polling (polling is BAD!!!). Use notifications instead. You can register for NSTask notifications that fire on producing output, or on ending the task, etc. You can also run the Task in such a way as to not proceed to the next step until it finishes executing. It's fairly versatile. Just read the manual.
     
wataru  (op)
Addicted to MacNN
Join Date: Oct 2001
Location: Yokohama, Japan
Status: Offline
Reply With Quote
Sep 5, 2005, 07:15 PM
 
I've read the documentation for NSTask. It only lists NSTaskDidTerminateNotification. Where are all these other notifications you're talking about?
     
Brass
Professional Poster
Join Date: Nov 2000
Location: Tasmania, Australia
Status: Offline
Reply With Quote
Sep 5, 2005, 10:03 PM
 
Sorry, my post was very misleading, and to be honest, completely incorrect, owing to the fact that I haven't looked at my own code for this for a long time.

What I actually did, was to use NSPipe/NSFileHandle as well as NSTask, and use their notifications to get output, etc (as well as the NSTask notification you mentioned).

I hope this helps a bit more this time.
     
wataru  (op)
Addicted to MacNN
Join Date: Oct 2001
Location: Yokohama, Japan
Status: Offline
Reply With Quote
Sep 6, 2005, 07:32 PM
 
I tried the CocoaDevCentral approach, but Brass's notification-based approach is much better. Thanks.

For posterity, what you do is:

1. Register your application controller or whatever to receive the appropriate notification:
Code:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(myMethod:) name:@"NSFileHandleReadCompletionNotification" object:nil];
2. Set the output of your NSTask to a pipe:
Code:
NSTask *task = [[NSTask alloc] init]; NSPipe *pipe = [[NSPipe alloc] init]; [task setStandardOutput:pipe];
3. Get a file handle from the pipe and start the monitoring process:
Code:
NSFileHandle *handle = [pipe fileHandleForReading]; [handle readInBackgroundAndNotify];
4. Begin the task as usual:
Code:
[task launch];
[font=Courier New]readInBackgroundAndNotify[/font] is not a repeated thing; it only notifies you once, so in [font=Courier New]myMethod:[/font] you will need to call it again if you want more notifications.
Code:
- (void)myMethod:(NSNotification *)note { // Get output string NSData *data = [[note userInfo] objectForKey:@"NSFileHandleNotificationDataItem"]; NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; // Do something with string blah blah blah // Ask for another notification if (condition) [[note object] readInBackgroundAndNotify]; [string release]; }
The only snafu I've found is that sometimes the task can output so quickly that [font=Courier New]string[/font] is several lines long. If you're expecting only one line, you can do:
Code:
NSString *oneLineString = [[string componentsSeparatedByString:@"\n"] objectAtIndex:0];
( Last edited by wataru; Sep 17, 2005 at 10:39 PM. )
     
Brass
Professional Poster
Join Date: Nov 2000
Location: Tasmania, Australia
Status: Offline
Reply With Quote
Sep 6, 2005, 08:17 PM
 
Yeah, that looks familiar. Glad I was able to help, after giving you completely the wrong info first time around!

The only other weird thing I've found with this kind of thing is a problem getting the last bit of output when a Task teminates, when there's lots of output, and I'm repeatedly getting notified. I can't remember the exact circumstances where it occured, but there appeared to be some annoying timing problem where the output came AFTER I got notified of the termination, but then I never got notified of the last bit of output.

But in general, it works well.
     
   
Thread Tools
 
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Top
Privacy Policy
All times are GMT -4. The time now is 02:58 PM.
All contents of these forums © 1995-2017 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.8 © 2000-2017, Jelsoft Enterprises Ltd.,