奇怪的GCD-Timer行为

时间:2014-11-03 15:13:24

标签: objective-c cocoa timer grand-central-dispatch

我遇到了一些奇怪的Grand Central Dispatch计时器行为。它打破了它的射击时间并冻结了几秒钟。虽然我需要ping我的服务器以保持“在线”,但这种行为非常不合适。

这里是计时器创建代码。

// pingTimer and pingQueue are class members
- (void)createPingTimerSource
  {
   // check timer exists
   if(pingTimer)
     {
      // suspend source and cancel
      [self setPingTimerSuspended:YES];
      dispatch_source_cancel(pingTimer);
     }
   // check having queue, create if doesn't exist
   if(!pingQueue)
       pingQueue = dispatch_queue_create(kDispatchTimerQueueLabel, NULL);
   // create timer dispatch source
   pingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, pingQueue);
   dispatch_source_set_timer(pingTimer, dispatch_time(DISPATCH_TIME_NOW, 5*NSEC_PER_MSEC), 5*NSEC_PER_MSEC, NSEC_PER_SEC/10);
   // set event handler
   dispatch_source_set_event_handler(pingTimer,^{
      printf("[%llu] gcd timer fired.\n", mach_absolute_time()/NSEC_PER_SEC);
      dispatch_async(dispatch_get_main_queue(), ^{
         [self sendPingToServer];
      });
   });
   // set cancel handler
   dispatch_source_set_cancel_handler(pingTimer, ^{
      // release dispatch source if exists
      if(pingTimer)
         dispatch_release(pingTimer);
      // check timer queue exists and release if does
      if(pingQueue)
         dispatch_release(pingQueue);
   });
  }

这里是日志控制台拍摄的。

Debug console content

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

dispatch_queue_create不保证它为处理块创建独立的线程。

以下是Apple documentation的引用 队列未绑定到任何特定的执行线程       提交给独立队列的块可以同时执行。

因此,这意味着如果您有许多处于压力下的队列,可能会导致您的pingQueue停止响应并执行具有延迟的块。

答案 1 :(得分:1)

有几种可能性:

  1. 您的pingQueue可能会被阻止执行某些操作,并且作为串行队列,它将无法执行新的调度块,直到先前的调度块完成并且队列再次可用。

    您可以尝试记录ping例程的启动和停止,并确保问题实际上是计时器触发失败而不是队列被阻止,因此无法接受新的计时器请求。

  2. 如果您的应用不在前台,“App Nap”功能可能会尝试合并定时器以最大限度地减少功耗。因此,可能不会以您期望的频率调用定时器。

    您可以通过提供DISPATCH_TIMER_STRICT作为dispatch_source_create的第三个参数来告知您的计时器不参与,尽管除非绝对需要(例如,与不能容忍计时器偏差的硬件接口),否则显然不鼓励这样做,如你失去了App Nap提供的节能。

    请参阅WWDC 2013 video Improving Power Efficiency with App Nap