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.
我理解,当iOS应用程序被放到后台时,所有子线程都被暂停。我的问题是,为什么操作系统会(随机地)杀死一个子线程?有时,当应用程序回到前台时,它可以正常工作,但有时子线程被终止。
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. 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.
好的,我可以重新复制它,它吐出操作完成了,所以[self]操作结束)是正确的。我不明白它是如何或为什么触发的,当它显然不是。我有一个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);
}
3 个解决方案
#1
1
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.
syncTimerRunning以什么方式终止?它这样做(可能是为了响应一个意外的错误)的可能性要大于操作系统杀死应用程序中的一个线程的可能性。
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?" Does the thread still exist when you attach a debugger and check the stack? What state is the thread in?
当你说“应用程序回来后”,你的意思是“线程继续运行一段时间后,应用willenterforground:,然后我不再看到它运行”,或者你的意思是“它再也不会运行了?”当您附加调试器并检查堆栈时,线程是否仍然存在?线程在哪个状态?
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
?
发生这种情况时队列中有哪些操作?NSOperation对象消失了吗?如果不是,它处于什么状态?标好了还是取消了?
#2
1
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
.
失败后,它自动终止线程,这就是为什么它将其设置为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之前添加了一个网络检查。
#3
0
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.
在这种情况下,最好在调试器中运行程序,并创建一个“异常断点”。NSOperation中的某些东西可能会导致抛出异常。如果是这种情况,那么断点将立即触发,您将拥有抛出异常的完整调用堆栈。
#1
1
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.
syncTimerRunning以什么方式终止?它这样做(可能是为了响应一个意外的错误)的可能性要大于操作系统杀死应用程序中的一个线程的可能性。
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?" Does the thread still exist when you attach a debugger and check the stack? What state is the thread in?
当你说“应用程序回来后”,你的意思是“线程继续运行一段时间后,应用willenterforground:,然后我不再看到它运行”,或者你的意思是“它再也不会运行了?”当您附加调试器并检查堆栈时,线程是否仍然存在?线程在哪个状态?
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
?
发生这种情况时队列中有哪些操作?NSOperation对象消失了吗?如果不是,它处于什么状态?标好了还是取消了?
#2
1
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
.
失败后,它自动终止线程,这就是为什么它将其设置为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之前添加了一个网络检查。
#3
0
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.
在这种情况下,最好在调试器中运行程序,并创建一个“异常断点”。NSOperation中的某些东西可能会导致抛出异常。如果是这种情况,那么断点将立即触发,您将拥有抛出异常的完整调用堆栈。