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.
CFRunLoopStop([runLoop getCFRunLoop]);
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With