Objective c 多线程中带有信号量的NSTask卡在waitUntilExit中
我的Cocoa应用程序有多个线程(最多8个线程),使用NSTask运行python脚本,大约需要1200秒。几乎在运行NSTask的8个线程的每次执行中,应用程序都会一直等待,而且永远不会返回。我暂停了执行,注意到应用程序卡在waitUntilExit中。 我的代码片段如下所示。请帮助让我知道如何解决这个问题Objective c 多线程中带有信号量的NSTask卡在waitUntilExit中,objective-c,multithreading,cocoa,semaphore,nstask,Objective C,Multithreading,Cocoa,Semaphore,Nstask,我的Cocoa应用程序有多个线程(最多8个线程),使用NSTask运行python脚本,大约需要1200秒。几乎在运行NSTask的8个线程的每次执行中,应用程序都会一直等待,而且永远不会返回。我暂停了执行,注意到应用程序卡在waitUntilExit中。 我的代码片段如下所示。请帮助让我知道如何解决这个问题 dispatch_semaphore_t MySemaphore; 首先,您不需要重复调用[filehandlewaitfordatainbackgroundandnotify
dispatch_semaphore_t MySemaphore;
首先,您不需要重复调用
[filehandlewaitfordatainbackgroundandnotify]代码>。可能不是你问题的根源
其次,在这种情况下,几乎总是因为缓冲问题。但你已经解决了这个问题。第二个最常见的原因是任务没有终止
您确定python脚本实际上正在终止吗?是的,我确定python脚本正在终止。您还建议我做什么来解决nstask waituntilexit中的“永远等待”问题?@user2370312除了确保从输出管道读取所有数据之外,我不确定。我在想,还有什么会阻止终止协议,结果是一片空白。
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];
}