2014-11-03 48 views
0

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

这里是计时器的创建代码。

// 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

谢谢你的帮助。

回答

1

几个可能的原因:

  1. pingQueue可能被阻塞做一些,作为一个串行队列,这将无法直到在先派送块饰面和队列进行新的调度块再次可用。

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

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

    你可以告诉你的计时器不通过提供DISPATCH_TIMER_STRICT作为第三个参数来dispatch_source_create参加,尽管这显然是不鼓励,除非绝对必要(例如,与无法忍受定时偏差硬件接口),因为你失去的节能应用午睡提供。

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

+0

是的,你说得对。谢谢你的帮助! – Astoria 2014-11-04 09:24:36

1

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

这里是Apple documentation
队列报价不一定要执行 并提交给独立的队列可以并发执行块的任何特定线程。

所以这意味着如果你有很多队列在压力下,可能会导致你的pingQueue停止响应并延迟执行块。