views:

489

answers:

2

Hi everyone,

I am writing an application which has to communicate with a device connected via USB. The app sends and receives data in turns from the device on a fixed timing. All Rx/Tx happens in a separate thread because otherwise the UI would be blocked. The basic structure looks basically like this. (autorelease pools and stuff omitted)

-(void)comThread:(id)arg {
  while(state == kIsConnected) {
    // let timers run
    [runLoop runUntilDate:[NSDate distantFuture]];
    // handle data
    if(rxTxState == kRx) {
      // do some stuff to pass data to upper layers
      rxTxState = kTx;
    }
    if(rxTxState == kTx) {
      // do some stuff to send data
      rxTimeoutTimer = [NSTimer scheduledTimer....];
    }
  } 
}

After sending data, the app waits for either data to be received or the rxTimeoutTimer to fire which leads to retransmission of the packet. The rx-operation works since the underlying layers use async system calls and calls a rx-handler which look basically like this.

-(void)receiveData:(NSData*)data{
  [rxQueue addObject:data];
  [rxTimeoutTimer invalidate];  // cancel timeout
}

Is there an (easy) way to make the [runLoop runUntilDate:] exit from receiveData:? The Apple docs say that removing all timer sources does not guarantee the RunLoop to exit. I read something about calling performSelector:onThread:... but it either did not work or I did not get the point.

Thanks.

+2  A: 
CFRunLoopStop([runLoop getCFRunLoop]);
KennyTM
Or, without the 'runLoop' local variable:CFRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]);
rpj
@rpj: You use `CFRunLoopGetCurrent()` in that case :)
KennyTM
+2  A: 

The standard pattern is to run the runloop for some timeout period (e.g. 0.5 seconds), and then iterate until the task is accomplished:

while(state == kIsConnected) {
  while(!iterationDone) {
    [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
    //do other stufff
  }
}

-(void)receiveData:(NSData*)data{
  [rxQueue addObject:data];
  [rxTimeoutTimer invalidate];  // cancel timeout
  iterationDone = YES;
}
Barry Wark
The whole timeout is 0.5 seconds in my case. I would have to run the RunLoop for fractions of this time like 0.05 seconds. I wonder if it really has this resolution.
insanelygreat
It really has this resolution.
rpj