开发者

Child thread randomly gets killed when app comes back to the foreground

开发者 https://www.devze.com 2023-04-01 01:08 出处:网络
I understand that when an iOS application gets put into the background, all child threads are put on hold. My question is why would the OS kill a child thread (randomly)? Sometimes when the app comes

I understand that when an iOS application gets put into the background, all child threads are put on hold. My question is why would the OS kill a child thread (randomly)? Sometimes when the app comes back to the foreground, it works fine, but other times the child thread is killed.

This is how I create the child thread:

NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] 
                                        initWithTarget:self
                                        selector:@selector(syncTimerRunning) 
                                        object:nil];
[queue addOperation:operation]; 
[operation release];

* Update *

Changed the code as follows, in a hope to debug it further.

self.queue = [NSOperationQueue new];
self.operation = [[NSInvocationOperation alloc] 
                                    initWithTarget:self
                                    selector:@selector(syncTimerRunning) 
                                    object:nil];
[self.queue addOperation:self.operation]; 

//[operation release];

Also checking the following in one of my NSTimer loops, to check if the thread is getting killed.

if([self.queue isSuspended]) {
    NSLog(@"queue is suspended");
}

if([self.operation isCancelled]) {
    NSLog(@"operation is cancelled");
}

if([self.operation isFinished]) {
    NSLog(@"operation is finished");
}

I haven't been able to reproduce the problem yet, after commenting out [operation release] and making it a class property, which gets released when class does.

* Another update *

I was under the impression that when you added an operation to queue, it retained it in memory, so that the operation release wouldn't have actually been the cause. Still attempting to reproduce the problem after the change.

* And another update *

Alright, I was able to reproduce it again, and it spit out operation is finished, so [self.operation isFinished] is true. I don't understand how or why it's triggering that as finished, when it's clearly not. I have an NSLog that should be triggered right before the child thread is finished - here is the syncTimerRunning method.

- (void) syncTimerRunning
{
    while (self.secondsCount > 0) {
        // need to query the server and get the current running timer and update the seconds
        TimeboxedEvent 开发者_如何学JAVA*te2 = [TimeboxedEvent getTimeboxedEvent:self.agentProfileId andIsPlayer:((self.gift == nil) ? YES : NO)];

        long timeLeft = (self.timeboxedEvent.timeBoxedEventTotalSeconds - (([te2.timeBoxedEventCurrentTimestamp longLongValue] - [te2.timeBoxedEventBeginTimestamp longLongValue]) / 1000));

        NSLog(@"retreived timebox: %@ - current time: %@ - time left: %ld - current seconds: %i", te2.timeBoxedEventBeginTimestamp, te2.timeBoxedEventCurrentTimestamp, timeLeft, self.secondsCount);

        if (timeLeft >= 0) {
            self.secondsCount = timeLeft;
        } else {
            self.secondsCount = 0;
        }

        sleep(10.0f);
    }

    NSLog(@"seconds count: %i", self.secondsCount);
}


What do you mean by "killed" and why do you believe it is happening? Have your verified that your application is not terminated between the time you enter the background and when you enter the foreground. If you are suspended, you will not receive a notification that you're being terminated.

In what ways can syncTimerRunning terminate? It is more likely that it is doing so (perhaps in response to an unexpected error) than that the OS is killing one thread in your application.

EDIT

What do you mean by "killed." Do you mean that you believe pthread_cancel() is called (why do you believe that?) or do you mean "my NSLog() entries no longer seem to show up?"

When you say "after the application comes back" do you mean "the thread continues to run for a while after applicationWillEnterForground:, and then I no longer see it running" or do you mean "it never appears to run again?" Does the thread still exist when you attach a debugger and check the stack? What state is the thread in?

What operations in in the queue when this happens? Does the NSOperation object go away? If not, what state is it in? Is it marked isCancelled or isFinished?


Well, I found the problem.

It was occasionally failing on this line:

TimeboxedEvent *te2 = [TimeboxedEvent getTimeboxedEvent:self.agentProfileId andIsPlayer:((self.gift == nil) ? YES : NO)];

After it failed, it automatically terminated the thread, which is why it was setting isFinished to YES.

It was failing because the phone would occasionally lose internet connectivity, which it required in order to do the sync. I just added an internet check before it called the getTimeboxedEvent and voila.


In cases like this it is good to run the program in the debugger and create a "breakpoint on exception". Probably something in your NSOperation causes an exception to be thrown. If this is the case, then the breakpoint will trigger immediately and you will have a complete call stack where the exception is thrown.

0

精彩评论

暂无评论...
验证码 换一张
取 消