why waitForDataInBackgroundAndNotify doesn't work with the real time monitor with more than 1 argument?

我的梦境 提交于 2019-12-12 01:34:55

问题


I have found the following code from one of the API, and I'm trying to use it to do a real time monitoring of vm_stat 1:

BOOL terminated = NO;

-(void)realTimeMonitor
{

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/bash"];
[task setArguments:[NSArray arrayWithObjects:@"-c", @"/usr/bin/vm_stat 1", nil]]; //works fine

// [task setArguments:[NSArray arrayWithObjects:@"-c", @"/usr/bin/vm_stat 1 | /usr/bin/awk '{print $1}'", nil]]; not working

NSPipe *pipe = [NSPipe pipe];
NSPipe *errorPipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task setStandardError:errorPipe];

NSFileHandle *outFile = [pipe fileHandleForReading];
NSFileHandle *errFile = [errorPipe fileHandleForReading];


[task launch];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(terminated:)
                                             name:NSTaskDidTerminateNotification
                                           object:task];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(outData:)
                                             name:NSFileHandleDataAvailableNotification
                                           object:outFile];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(errData:)
                                             name:NSFileHandleDataAvailableNotification
                                           object:errFile];


[outFile waitForDataInBackgroundAndNotify];
[errFile waitForDataInBackgroundAndNotify];
while(!terminated)
{
    if (![[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])
    {
        break;
    }
}
}

-(void) outData: (NSNotification *) notification
{
NSFileHandle *fileHandle = (NSFileHandle*) [notification object];
NSData *data = [fileHandle availableData];

if ([data length]) {

    NSString *currentString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    // do something 
}

[fileHandle waitForDataInBackgroundAndNotify]; //Checks to see if data is available in a background thread.
}


-(void) errData: (NSNotification *) notification
{
NSLog(@"errData");
NSFileHandle *fileHandle = (NSFileHandle*) [notification object];
[fileHandle waitForDataInBackgroundAndNotify];
}

- (void) terminated: (NSNotification *)notification
{
NSLog(@"Task terminated");
[[NSNotificationCenter defaultCenter] removeObserver:self];
terminated =YES;
}

========

Please look at the setArguments lines. The first one works perfectly fine "/usr/bin/vm_stat 1", however the second line doesn't work "/usr/bin/vm_stat 1 | /usr/bin/awk '{print $1}' " (no output at all), but if I run it on terminal it works perfectly fine. why is that?


回答1:


Maybe awk is buffering its stdout stream because it thinks it does not write its stdout stream to a tty device.

This may eventually lead to a complete deadlock since it may become impossible for vm_stat to write to its stdout if awk's stdin gets filled up and there is no consumer onawk's stdout.

Therefore try flushing awk's stdout using its built-in fflush() function.

[task setArguments:[NSArray arrayWithObjects:@"-c", @"/usr/bin/vm_stat 1 | /usr/bin/awk '{print $1; fflush();}'", nil]]; 

I was able to run your code using (slightly modified) asynctask.m.



来源:https://stackoverflow.com/questions/14408456/why-waitfordatainbackgroundandnotify-doesnt-work-with-the-real-time-monitor-wit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!