Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSTask blocks main thread

From my main thread I call a selector using

[self performSelectorInBackground:@selector(startTask) withObject:nil];

This is the method startTask:

-(void)startTask{    
   NSTask *task = [[NSTask alloc] init];
   NSPipe *pipe = [[NSPipe alloc] init];
   NSFileHandle *fh = [pipe fileHandleForReading];

   NSArray *args = [NSArray arrayWithObjects:@"-z",iPAddress, [NSString stringWithFormat:@"%@",portNumber], nil];

   [task setLaunchPath:@"/usr/bin/nc"];
   [task setArguments:args];
   [task setStandardOutput:pipe];

   NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
   [nc removeObserver:self];
   [nc addObserver:self
          selector:@selector(dataReady:)
              name:NSFileHandleReadCompletionNotification
            object:fh];

   [task launch];
   [fh readInBackgroundAndNotify];
}

This should prevent NSTask from blocking the main thread (and the UI). But it doesn't. If I remove

[task launch];

The main thread doesn't get blocked. What am I doing wrong? o_O

(BTW dataReady just handles the data. It's not this method, that blocks...)

EDIT: I just found out, that I am not calling the selector from the main thread. I call it from a separate thread! Unfortunately I have to call it from that thread.

like image 906
Daniel Avatar asked May 17 '26 04:05

Daniel


2 Answers

I don't know if this is the answer to your question, but you do have a fundamental issue:

The docs for readInBackgroundAndNotify say:

You must call this method from a thread that has an active run loop.

You are not doing that because startTask is on its own thread and you are not running a run loop on it.

like image 114
JeremyP Avatar answered May 18 '26 17:05

JeremyP


I'm not sure what the issue is but I suggest looking into NSOperationQueue.

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^(void) {
   NSTask *task = [[NSTask alloc] init];
   NSPipe *pipe = [[NSPipe alloc] init];
   NSFileHandle *fh = [pipe fileHandleForReading];

   NSArray *args = [NSArray arrayWithObjects:@"-z",iPAddress, [NSString stringWithFormat:@"%@",portNumber], nil];

   [task setLaunchPath:@"/usr/bin/nc"];
   [task setArguments:args];
   [task setStandardOutput:pipe];

   NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
   [nc removeObserver:self];
   [nc addObserver:self
          selector:@selector(dataReady:)
              name:NSFileHandleReadCompletionNotification
            object:fh];

   [task launch];
}];
[queue autorelease];

Lemme know if you have any questions

In the documentation heres some info on NSOperationQueue just if you were wondering:

Operation queues usually provide the threads used to run their operations. In Mac OS X v10.6 and later, operation queues use the libdispatch library (also known as Grand Central Dispatch) to initiate the execution of their operations. As a result, operations are always executed on a separate thread, regardless of whether they are designated as concurrent or non-concurrent operations.

like image 42
DanZimm Avatar answered May 18 '26 18:05

DanZimm