2014-11-03 279 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停止響應並延遲執行塊。