2015-05-29 121 views
0

我的可可應用程序有多線程(最多8個線程)運行一個使用NSTask約需1200秒的Python腳本。幾乎在運行NSTask的8個線程的每個執行過程中,該應用程序幾乎永遠等待並永不返回。我暫停了執行,發現應用程序停留在waitUntilExit中。 我的代碼片段如下。請幫助讓我知道我可以如何解決這個問題。NSTask信號量在多重卡住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

首先,你不需要重複調​​用[fileHandle waitForDataInBackgroundAndNotify];。可能不是你的問題的來源...

其次,在這些情況下,它幾乎總是因爲緩衝問題。但你已經解決了這個問題。第二個最常見的原因是任務沒有終止。

你確定python腳本實際上是終止的嗎?

+0

是的我確定Python腳本正在終止。你還建議我做什麼來解決這個問題,在nstask waituntilexit問題上「永遠等待」? – user2370312

+0

@ user2370312除了確保從輸出管道讀取所有數據之外,我不確定。我試圖想想還有什麼會阻止終止,併成爲空白。 – bbum