【问题标题】:NSTask: why program is blocking when read from NSPipe?NSTask:为什么从 NSPipe 读取程序会阻塞?
【发布时间】:2013-09-16 15:19:50
【问题描述】:

我使用 NSTask 运行 shell 命令并通过 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 是我想要的,但是在附加最后一个数据块之后,它被阻塞了。 你能给我一些解决方案吗?谢谢。

【问题讨论】:

    标签: objective-c blocking nstask nspipe


    【解决方案1】:

    您的while() 循环有效地阻止了进一步的通知,导致整个程序阻塞等待刷新缓冲区的内容。

    您应该readInBackgroundAndNotify,然后在每个通知上取消availableBytes,将其附加到您的NSMutableData(可能保存在实例变量中)。当您处理通知时,不要尝试等待更多数据或执行任何类型的while 循环。当有更多可用数据时,系统会通知您。

    即系统将数据推送给您,您不会从系统中提取数据。


    啊……好的。您仍然应该仅在有可用数据时提取数据。您的 while() 循环正在这样做。咖啡不够。我的错。

    最后一个块很可能是因为您的外部进程没有关闭管道;没有收到 EOF,因此程序一直在等待更多永远不会到达的数据。

    要么:

    • 确保后台任务退出

    • 检测何时收到足够的数据并终止进程

    如果您正在执行某种类型的转换程序(例如,tr),您在进程标准输入上写入数据,那么您可能需要关闭标准输入管道。

    【讨论】:

    • 我真的不明白,对不起。你能提供任何代码来证明它吗?谢谢。
    • 你说while 循环阻止进一步的通知。但是while循环逐块接收所有数据,也就是说,数据完全被while循环接收。阻塞只发生在最后一个块数据(
    • @bbbum,感谢您的帮助。现在我知道为什么了。不幸的是,我无法退出后台任务,因为我的应用程序想要与 shell 交互(例如,启动 sh,并通过管道输入命令)。至于第二种方式,我不知道何时以及如何检测数据量。我找到了一个example,它谈到了问题的解决方案,但它对我无效。我需要你的进一步帮助。再次感谢。
    • @GateLuma 正在读取的数据是什么格式?通常,在任何给定的协议/格式中,都会有某种方式知道何时收到了所有数据。除此之外,您必须拥有某种信号机制,这需要修改您正在运行的任何外部工具的代码。
    • 数据是执行的shell命令的输出,例如“ls”或“system_profiler”。这个问题有简单的解决方案吗?
    猜你喜欢
    • 2012-11-03
    • 1970-01-01
    • 2013-03-10
    • 1970-01-01
    • 2010-11-28
    • 1970-01-01
    • 2017-04-26
    • 1970-01-01
    相关资源
    最近更新 更多