我的Cocoa App有多线程(最多8个线程)使用NSTask运行python脚本,大约需要1200秒。几乎在运行NSTask的8个线程的每次执行中,应用程序几乎永远等待并且永远不会返回。我暂停执行,发现应用程序卡在waitUntilExit中。 我的代码片段如下。请帮助告诉我如何解决这个问题。
dispatch_semaphore_t MySemaphore;
...
MySemaphore = dispatch_semaphore_create(8);
...
//Code portion where NSTask is used to execute a python script.
...
NSTask* task = [NSTask new];
[task setLaunchPath:launchPath];
[task setArguments:[NSArray arrayWithObjects:param1,
param2, param3,
param4, param5,
param6, param7, nil]];
NSData *outData;
NSData *errorData;
int retVal;
dispatch_semaphore_wait(MySemaphore, DISPATCH_TIME_FOREVER);
retVal = [self _runTask:task
inData:nil
outData:&outData
errorData:&errorData];
dispatch_semaphore_signal(MySemaphore);
NSMutableString *retStr = [[[NSMutableString alloc] initWithData:outData
encoding:NSUTF8StringEncoding] autorelease];
NSMutableString *retStrErr = [[[NSMutableString alloc] initWithData:errorData
encoding:NSUTF8StringEncoding] autorelease];
if([retStrErr length] != 0)
{
[retStr appendString:@"\nstandard Error output:\n"];
[retStr appendString:retStrErr];
}
if( retVal == 0 )
{
[retStr appendString:@"\nOK\n"];
}
else
{
[retStr appendString:@"\nERROR\n"];
}
NSLog(@"Response of _DRAMRetention for UUT:%d, %@", nUut+1, retStr);
[task release];
...
- (int) _runTask:(NSTask*)task inData:(NSData*)inData outData:(NSData**)outData errorData:(NSData**)errorData
{
NSPipe* inPipe = nil;
NSPipe* outPipe = nil;
NSPipe* errorPipe = nil;
NSFileHandle* fileHandle;
/* Reset output variables */
if(outData)
{
*outData = nil;
}
if(errorData)
{
*errorData = nil;
}
/* Safe check */
if(task == nil)
{
return -1;
}
/* Create standard input pipe */
if([inData length])
{
if((inPipe = [NSPipe new]))
{
[task setStandardInput:inPipe];
[inPipe release];
}
else
{
task = nil;
goto Exit;
}
}
/* Create standard output pipe */
if(outData)
{
if((outPipe = [NSPipe new]))
{
[task setStandardOutput:outPipe];
[outPipe release];
}
else
{
task = nil;
goto Exit;
}
}
/* Create standard error pipe */
if(errorData)
{
if((errorPipe = [NSPipe new]))
{
[task setStandardError:errorPipe];
[errorPipe release];
}
else
{
task = nil;
goto Exit;
}
}
/* Launch task */
NS_DURING
[task launch];
NS_HANDLER
task = nil;
NS_ENDHANDLER
if(task == nil)
{
goto Exit;
}
/* Write data to standard input pipe */
if((fileHandle = [inPipe fileHandleForWriting]))
{
NS_DURING
[fileHandle writeData:inData];
[fileHandle closeFile];
NS_HANDLER
[task terminate];
[task interrupt];
task = nil;
NS_ENDHANDLER
}
if(task == nil)
{
goto Exit;
}
/* Wait for task to complete and read data from standard output and standard error pipes in background */
if((fileHandle = [outPipe fileHandleForReading]))
{
*outData = [NSMutableData data];
[[NSNotificationCenter defaultCenter] addObserver:*outData selector:@selector(_CommandLineToolFileHandleDataAvailable:) name:NSFileHandleDataAvailableNotification object:fileHandle];
[fileHandle waitForDataInBackgroundAndNotify];
}
if((fileHandle = [errorPipe fileHandleForReading]))
{
*errorData = [NSMutableData data];
[[NSNotificationCenter defaultCenter] addObserver:*errorData selector:@selector(_CommandLineToolFileHandleDataAvailable:) name:NSFileHandleDataAvailableNotification object:fileHandle];
[fileHandle waitForDataInBackgroundAndNotify];
}
//My app is stuck here
[task waitUntilExit];
if((fileHandle = [errorPipe fileHandleForReading]))
{
[[NSNotificationCenter defaultCenter] removeObserver:*errorData name:NSFileHandleDataAvailableNotification object:fileHandle];
[(NSMutableData*)*errorData appendData:[fileHandle readDataToEndOfFile]];
}
if((fileHandle = [outPipe fileHandleForReading]))
{
[[NSNotificationCenter defaultCenter] removeObserver:*outData name:NSFileHandleDataAvailableNotification object:fileHandle];
[(NSMutableData*)*outData appendData:[fileHandle readDataToEndOfFile]];
}
Exit:
[[inPipe fileHandleForReading] closeFile];
[[inPipe fileHandleForWriting] closeFile];
[[outPipe fileHandleForReading] closeFile];
[[outPipe fileHandleForWriting] closeFile];
[[errorPipe fileHandleForReading] closeFile];
[[errorPipe fileHandleForWriting] closeFile];
return (task ? [task terminationStatus] : -1);
}
@end
@implementation NSMutableData (CommandLineTool)
/* Extend the NSMutableData class to add a method called by NSFileHandleDataAvailableNotification to automatically append the new data */
- (void) _CommandLineToolFileHandleDataAvailable:(NSNotification*)notification
{
NSFileHandle* fileHandle = [notification object];
[self appendData:[fileHandle availableData]];
[fileHandle waitForDataInBackgroundAndNotify];
}
答案 0 :(得分:0)
首先,您不需要反复拨打[fileHandle waitForDataInBackgroundAndNotify];
。可能不是你问题的根源......
其次,在这些情况下,几乎总是因为缓冲问题。但是你已经解决了这个问题。第二个最常见的原因是任务没有终止。
你确定python脚本实际上正在终止吗?