带有多线程信号量的NSTask卡在waitUntilExit中

时间:2015-05-29 15:45:08

标签: objective-c multithreading cocoa semaphore nstask

我的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];
}

1 个答案:

答案 0 :(得分:0)

首先,您不需要反复拨打[fileHandle waitForDataInBackgroundAndNotify];。可能不是你问题的根源......

其次,在这些情况下,几乎总是因为缓冲问题。但是你已经解决了这个问题。第二个最常见的原因是任务没有终止。

你确定python脚本实际上正在终止吗?