> Possibly unrelated to your issue with the dispatch threads (although possibly > related), the above use of NSTask is somewhat broken. You've made a common > mistake. It is not OK to block waiting for the task to exit when you haven't > established an ongoing asynchronous read of its output (when you're capturing > the output rather than letting it go to file, /dev/console, or /dev/null, > etc.). > > The problem is that pipes have a fixed buffer in the kernel. If a task > writes more than that amount to the pipe when no reader is draining the pipe, > the writer blocks. You don't read from the pipe until after the task has > exited, but the task may be prevented from exiting because you're not reading > from the pipe. Classic deadlock. > > Put another way, have you confirmed that your tasks are really completing? > Maybe the dispatch threads are still alive because of this deadlock I'm > describing. (I guess it depends on whether your "ls -l -a -t" command is > producing more output than the size of a pipe's buffer, which in turn depends > on the current working directory and its contents.)
Thanks again Ken for you suggestion on this bug and on the last one to do with NSTask. Right, I have changed the example a bit so that the NSTask in this case is using notifications. I also get it to print the output. Actually now I can see this is reproducing the old problem I had of some of the output results being just simply dropped. Eg Here is the new code (header): @interface ShellTask : NSObject { NSString* generatingCmd_; // The command that was executed NSArray* generatingArgs_; // The arguments used to the command int result_; // The result of executing the command NSTask* task_; // The NSTask we are trying to perform NSFileHandle* outHandle_; NSFileHandle* errHandle_; NSMutableData* outputData_; NSMutableData* errorData_; } @property (nonatomic, assign) NSTask* task; + (void) execute:(NSString*)cmd withArgs:(NSArray*)args; @end Here is the new code (body): ------------------------------- - (void) doWorkerLaunches { for (int i = 1; i <50; i++) { dispatch_async(dispatch_get_global_queue(0,0), ^{ [ShellTask execute:@"/bin/ls" withArgs:[NSArray arrayWithObjects: @"-l", @"-a", @"-t", nil]]; }); } } @implementation ShellTask @synthesize task = task_; - (void) gotOutput:(NSNotification*)notification { NSData* data = [notification.userInfo objectForKey:NSFileHandleNotificationDataItem]; if (notification.object == outHandle_) { if (data.length > 0) { [outputData_ appendData:data]; [outHandle_ readInBackgroundAndNotify]; } else outHandle_ = nil; } } - (void) gotError:(NSNotification*)notification { if (notification.object == errHandle_) { NSData* data = [notification.userInfo objectForKey:NSFileHandleNotificationDataItem]; if (data.length > 0) { [errorData_ appendData:data]; [errHandle_ readInBackgroundAndNotify]; } else errHandle_ = nil; } } - (BOOL) waitTillFinished { [task_ waitUntilExit]; [[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:nil]; [task_ terminate]; result_ = [task_ terminationStatus]; outHandle_ = nil; errHandle_ = nil; return (result_ == 0); } - (id) initWithCommand:(NSString*)cmd andArgs:(NSArray*)args { generatingCmd_ = cmd; generatingArgs_ = args; task_ = [[NSTask alloc] init]; NSPipe* outPipe = [[NSPipe alloc] init]; // Create the pipe to write standard out to NSPipe* errPipe = [[NSPipe alloc] init]; // Create the pipe to write standard error to outHandle_ = [outPipe fileHandleForReading]; errHandle_ = [errPipe fileHandleForReading]; outputData_ = [[NSMutableData alloc] init]; errorData_ = [[NSMutableData alloc] init]; [task_ setLaunchPath:cmd]; [task_ setArguments:args]; [task_ setStandardInput:[NSPipe pipe]]; [task_ setStandardOutput:outPipe]; [task_ setStandardError:errPipe]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(gotOutput:) name:NSFileHandleReadCompletionNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(gotError:) name:NSFileHandleReadCompletionNotification object:nil]; [outHandle_ readInBackgroundAndNotify]; [errHandle_ readInBackgroundAndNotify]; return self; } + (void) execute:(NSString*)cmd withArgs:(NSArray*)args { ShellTask* shellTask = [[ShellTask alloc] initWithCommand:cmd andArgs:args]; [shellTask->task_ launch]; // Start the process [shellTask waitTillFinished]; NSString* outStr = [[NSString alloc] initWithData:shellTask->outputData_ encoding:NSUTF8StringEncoding]; NSString* errStr = [[NSString alloc] initWithData:shellTask->errorData_ encoding:NSUTF8StringEncoding]; fprintf(stderr, "output:\n%s\n", [outStr UTF8String]); if ([errStr length] > 0) fprintf(stderr, "error:\n%s\n", [errStr UTF8String]); } @end ------------- Interestingly now the output now just looks like: output: total 0 drwxr-xr-x 3 jason staff 102 Mar 27 23:57 gcdGroups.app drwxr-xr-x 3 jason staff 102 Mar 27 23:02 . drwxr-xr-x@ 4 jason staff 136 Mar 27 23:02 .. output: total 0 drwxr-xr-x 3 jason staff 102 Mar 27 23:57 gcdGroups.app drwxr-xr-x 3 jason staff 102 Mar 27 23:02 . drwxr-xr-x@ 4 jason staff 136 Mar 27 23:02 .. output: output: output: total 0 drwxr-xr-x 3 jason staff 102 Mar 27 23:57 gcdGroups.app drwxr-xr-x 3 jason staff 102 Mar 27 23:02 . drwxr-xr-x@ 4 jason staff 136 Mar 27 23:02 .. output: output: output: output: output: total 0 drwxr-xr-x 3 jason staff 102 Mar 27 23:57 gcdGroups.app drwxr-xr-x 3 jason staff 102 Mar 27 23:02 . drwxr-xr-x@ 4 jason staff 136 Mar 27 23:02 .. output: output: total 0 drwxr-xr-x 3 jason staff 102 Mar 27 23:57 gcdGroups.app drwxr-xr-x 3 jason staff 102 Mar 27 23:02 . drwxr-xr-x@ 4 jason staff 136 Mar 27 23:02 .. So you can see various tasks where just "skipped". I think this corresponds to the cases where maybe the DispatchWorker is not quitting... Complete ready to run project and code is at: http://jasonfharris.com/files/misc_snippets/gcdGroupsNotifications.zip_______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com