Re: GCD dispatch workers and termination
Re: GCD dispatch workers and termination
- Subject: Re: GCD dispatch workers and termination
- From: Jason Harris <email@hidden>
- Date: Mon, 28 Mar 2011 00:25:30 +0200
> 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.)
BTW, I tried your suggested approach of manually creating the pipe's. The full code I used for that trial is at:
http://jasonfharris.com/files/misc_snippets/gcdGroupsNotificationsManualPipes.zip
Basically the two main changes are:
- (id) initWithCommand:(NSString*)cmd andArgs:(NSArray*)args
{
generatingCmd_ = cmd;
generatingArgs_ = args;
task_ = [[NSTask alloc] init];
int createStdOutPipe = pipe(stdoutPipe_fds);
int createStdErrPipe = pipe(stderrPipe_fds);
if (createStdOutPipe != 0)
fprintf(stderr, "couldn't create pipe\n");
if (createStdErrPipe != 0)
fprintf(stderr, "couldn't create pipe\n");
outReadHandle_ = [[NSFileHandle alloc] initWithFileDescriptor:stdoutPipe_fds[0]];
outWriteHandle_ = [[NSFileHandle alloc] initWithFileDescriptor:stdoutPipe_fds[1]];
errReadHandle_ = [[NSFileHandle alloc] initWithFileDescriptor:stderrPipe_fds[0]];
errWriteHandle_ = [[NSFileHandle alloc] initWithFileDescriptor:stderrPipe_fds[1]];
[task_ setStandardOutput:outWriteHandle_];
[task_ setStandardError:errWriteHandle_];
outputData_ = [[NSMutableData alloc] init];
errorData_ = [[NSMutableData alloc] init];
[task_ setLaunchPath:cmd];
[task_ setArguments:args];
[task_ setStandardInput:[NSPipe pipe]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(gotOutput:) name:NSFileHandleReadCompletionNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(gotError:) name:NSFileHandleReadCompletionNotification object:nil];
[outReadHandle_ readInBackgroundAndNotify];
[errReadHandle_ 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->outWriteHandle_ release];
[shellTask->errWriteHandle_ release];
close(shellTask->stdoutPipe_fds[1]);
close(shellTask->stderrPipe_fds[1]);
[shellTask waitTillFinished];
[shellTask->outReadHandle_ release];
[shellTask->errReadHandle_ release];
close(shellTask->stdoutPipe_fds[0]);
close(shellTask->stderrPipe_fds[0]);
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]);
}
---------------------
Unfortunately this still seems to have the same behavior as before, but I might have done something wrong here... Its still "skipping" doing various tasks. If I put in a delay on the launch of each task of around .2 seconds then many fewer tasks are "skipped" but still clearly it appears something is going on.
Have I set up the NSTasks wrong? Or is the lower level code failing when it is getting simultaneous task requests?
Cheers & Thanks,
Jas
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden