GCD与超过255秒的任何任务崩溃

问题描述:

以下代码在iOS模拟器中产生崩溃。GCD与超过255秒的任何任务崩溃

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     NSDate *sleepStart = [NSDate date]; 
     while ([sleepStart timeIntervalSinceNow] > -300) { 

     } 
    });  
} 

更新:即使发生在后台线程此问题。

下面的代码也是越野车:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     NSDate *sleepStart = [NSDate date]; 
     while ([sleepStart timeIntervalSinceNow] > -300) { 

     } 
    });  
} 

这就是全部。将其粘贴到任何视图控制器中,在模拟器中运行该应用程序正好4分15秒,并且会崩溃。

这次撞车是我从未见过的一种类型。这是“EXC _ ???(11)”。奇怪的是,你可以在崩溃后按下继续按钮,它会像平常一样继续。

为什么会崩溃?如何将长期任务提交给队列而不会导致此行为?

这里有一些事情到目前为止,我已经试过了,已经摆脱无光任何的奥秘:

  • 创建我自己的调度队列(包括后台线程的)
  • 使用NSBlockOperation代替的GCD(仍然崩溃)
  • 插入睡眠。短时间睡眠(5秒左右)似乎可以延缓睡眠时的崩溃。更长的睡眠似乎做了更多。所以如果你一次睡五秒钟,它将会以4米20秒的速度而不是4米15秒的速度崩溃。如果你一次睡60秒,大概需要十分钟才能崩溃,但最终会发生。这个线索似乎很重要,但我不知道它可能意味着什么。

更新#1

的问题仅LLDB,不GDB下再现。

+3

你举起了主线?是的,它会崩溃。 – 2013-03-04 03:38:23

+2

为了扩大这个范围:iOS发现你的应用一直没有响应(对任何事件没有响应)时间过长,并且因为这意味着你的应用被破坏,它会杀死你的应用。你不应该超过1/60秒,更不用说4分钟了。为什么不在一个并发队列中运行此块? – 2013-03-04 03:42:59

+0

问题更新后,行为与主队列是否被阻止或后台队列无关。 – Drew 2013-03-04 05:29:28

Apple engineer

的“崩溃”你看到的是不是真的崩溃,其日志时 应用程序使用太多CPU时间持续一段时间。它的 存在的理由是告诉你不要这样做,并且CPU时间 正在花费。在生产中,日志会被简单地记录下来,并且您的过程应该继续。但是如果你能避免这些类型的日志,那就更好了。

及更高版本:

您应该提交错误报告。 lldb应该足够聪明以默认忽略该陷阱。

您不能在主线程上执行冗长的操作。您应该将块分派给另一个线程,然后在块的末尾派送回主线程(如果需要的话)。

使用dispatch_async(dispatch_get_main_queue(),^{});会导致您的操作在不久的将来在主线程上执行(阻塞)。

主线程受计时器保护;如果你停止响应事件,iOS会终止它。这是故意的:不要在主线上举重!

iOS的容忍度通常是,远远低于4分钟的,但如果您正在调试,它会变得更长。模拟器有其自己的规则。

在启动时,这只是几秒钟的事情。但是你不应该在主线程上花费不止一秒的时间,而只是在直接用户操作(例如用户点击某件事)时做出响应。在主线程上工作会导致iOS界面变得不太灵敏,而不是平滑。

如果您的应用程序停止响应OSX上主线程上的事件,它就是沙滩球。你的应用停止响应iOS上主线程的事件,iOS看门狗将它取出并拍摄。

TechNote TN2151

异常代码0x8badf00d指出一个应用程序已经被终止的iOS因为看门狗超时发生。应用程序花费太长时间才能启动,终止或响应系统事件。其中一个常见原因是在主线程上进行同步联网。无论线程0上的操作如何:需要移动到后台线程,或者以不同的方式处理,以便它不会阻塞主线程。

一般来说,模式是:

- (IBAction)tappedWhatever:(id)sender { 
    // visually start operation 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{ 
     // do work here, off main thread 
     // (you can't update the UI here) 
     dispatch_async(dispatch_get_main_queue(),^{ 
      // show progress in UI 
     }); 
     // more heavy lifting 
     dispatch_async(dispatch_get_main_queue(),^{ 
      // update UI to show operation complete and move to next step 
     }); 
    }); 
}; 

(?我可以发誓,有这个苹果的文档更好的说明,但现在我找不到它的任何人)

+0

有趣的是“沙滩球”官方术语xD?我一直把它称为“死亡的糖果轮” – borrrden 2013-03-04 03:48:49

+0

我一直很喜欢旋转比萨,但沙滩球似乎赢了。 :) – 2013-03-04 03:49:28

+1

“我很惊讶超时设置了这么长时间” - 也许是因为他正在模拟器中尝试它?在设备上,看门狗应该在10秒内杀死他。 – matt 2013-03-04 03:54:25