2013-09-16 50 views
0

我使用NSTask來運行shell命令並通過NSPipe輸出數據。起初,我使用波紋管方法來讀取輸出數據,這沒有任何問題。NSTask:爲什麼程序在從NSPipe讀取時被阻塞?

- (void)outputAvailable:(NSNotification *)aNotification { 
    NSString *newOutput; 
    NSMutableData *allData = [[NSMutableData alloc] init]; 
    NSData *taskData = nil;   
    if((taskData = [readHandle availableData]) && [taskData length]) 
    newOutput = [[NSString alloc] initWithData:allData encoding:NSASCIIStringEncoding]; 
    NSLog(@"%@", newOutput); 
    [readHandle readInBackgroundAndNotify];  
} 

該方法的問題是它只輸出4096字節的數據。所以我用while循環,以獲得更多的數據,修改方法如下:發生

- (void)outputAvailable:(NSNotification *)aNotification { 
    NSString *newOutput; 
    NSMutableData *allData; //Added. 
    NSData *taskData = nil; 
    while ((taskData = [readHandle availableData]) && [taskData length]) { 
    [allData appendData:taskData]; 
    }  
    newOutput = [[NSString alloc] initWithData:allData encoding:NSASCIIStringEncoding]; 
    NSLog(@"%@", newOutput); 
    [readHandle readInBackgroundAndNotify]; 
} 

然後的問題:程序在while循環阻塞,不能執行以下語句。我確保allData是我想要的,但在追加最後一個數據塊後,它會被阻塞。 你能給我一些解決方案嗎?謝謝。

回答

0

你的while()循環有效地阻止了進一步的通知,導致整個程序阻塞等待某些東西刷新緩衝區。

您應該readInBackgroundAndNotify,然後在每個通知上關閉availableBytes,將其附加到您的NSMutableData(可能保存在實例變量中)。處理通知時,請勿嘗試等待更多數據或執行任何種類的循環。系統會在有更多數據可用時通知您。

I.e.系統會向您推送數據,您不會從系統中提取數據。


啊......好的。當有數據可用時,您仍應該只提取數據。你的while()循環就是這樣做的。沒有足夠的咖啡。我的錯。

最後的塊很可能是因爲你的外部進程沒有關閉管道;沒有收到EOF,因此,程序正在永遠等待更多永遠不會到達的數據。

或者:

  • 確保後臺任務退出

  • 檢測,當你已經收到了足夠的數據和終止進程

如果你正在做某種轉換程序(例如,tr),其中您在過程標準輸入上寫入數據,則可能需要關閉標準輸入管道。

+0

我真的不明白,對不起。你能提供任何代碼來證明它嗎?謝謝。 –

+0

你說'while'循環blokcs進一步的通知。但是'while'循環通過塊接收所有的數據塊,也就是說,數據完全由'while'循環接收。阻塞只發生在最後一個塊數據(<4096bytes)接收之後。 –

+0

@bbbum,感謝您的幫助。現在我知道爲什麼。不幸的是,我不能退出後臺任務,因爲我的應用程序想要與shell交互(例如通過管道啓動sh和輸入命令)。至於第二種方法,我不知道何時以及如何檢測數據量。我找到了一個[示例](http://dev.notoptimal.net/2007/04/nstasks-nspipes-and-deadlocks-when.html),它討論了該問題的解決方案,但它對我無效。我需要你的進一步幫助。再次感謝。 –

相關問題