简体   繁体   English

当应用程序返回前台时,子线程随机被杀死

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

I understand that when an iOS application gets put into the background, all child threads are put on hold. 我知道当iOS应用程序进入后台时,所有子线程都被置于保持状态。 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. 还要在我的一个NSTimer循环中检查以下内容,以检查线程是否被杀死。

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. 在评论出[operation release]并使其成为类属性之后,我还没有能够重现这个问题。

* 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. 好吧,我能够再次重现它,并且吐出operation is finished ,所以[self.operation isFinished]是真的。 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. 我有一个NSLog应该在子线程完成之前触发 - 这是syncTimerRunning方法。

- (void) syncTimerRunning
{
    while (self.secondsCount > 0) {
        // need to query the server and get the current running timer and update the seconds
        TimeboxedEvent *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? syncTimerRunning以什么方式终止? 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. 它更可能是这样做(可能是为了响应意外错误),而不是OS正在杀死应用程序中的一个线程。

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?" 你的意思是你相信pthread_cancel()被调用(为什么你相信?)或者你的意思是“我的NSLog()条目似乎不再显示?”

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?" 当你说“在应用程序回来之后”你的意思是“在applicationWillEnterForground:之后线程继续运行一段时间,然后我不再看到它在运行”或者你的意思是“它似乎永远不会再次运行?” 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? NSOperation对象会消失吗? If not, what state is it in? 如果没有,它处于什么状态? Is it marked isCancelled or isFinished ? 难道它标志着isCancelledisFinished

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 . 失败后,它会自动终止线程,这就是将isFinished设置为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. 我在调用getTimeboxedEvent之前添加了一个互联网检查。

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. 你的NSOperation某些东西可能会引发异常。 If this is the case, then the breakpoint will trigger immediately and you will have a complete call stack where the exception is thrown. 如果是这种情况,那么断点将立即触发,您将拥有一个完整的调用堆栈,其中抛出异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM