Daniyar
Daniyar

Reputation: 3003

Strange GCD-Timer behavior

I faced with some strange Grand Central Dispatch timer behavior. It breaks its period of firing and freezes for many seconds. While I need to ping my server to stay "online", this behavior is strongly unsuitable.

Here the timer creation code.

// 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);
   });
  }

Here the log console shot.

Debug console content

Thank you for help.

Upvotes: 0

Views: 377

Answers (2)

Rob
Rob

Reputation: 438232

A couple of possibilities:

  1. Your pingQueue might be blocked doing something, and as a serial queue, it won't be able to perform new dispatched blocks until the prior dispatched block finishes and the queue once again available.

    You might try logging the starting and stopping of your ping routine, and make sure that the problem is really the failure of the timer to fire and not that the queue is blocked and therefore cannot honor new timer requests.

  2. If your app is not in foreground, the "App Nap" feature may try to coalesce timers to minimize power drain. Thus the timers may not be called with the frequency that you expected.

    You can tell your timer to not participate by supplying DISPATCH_TIMER_STRICT as the third parameter to dispatch_source_create, though this is obviously discouraged unless absolutely needed (e.g. interfacing with hardware that cannot tolerate timer deviation), as you lose the power savings App Nap provides.

    See WWDC 2013 video Improving Power Efficiency with App Nap.

Upvotes: 1

l0gg3r
l0gg3r

Reputation: 8954

dispatch_queue_create doesn't guarantee you that it creates independent thread for processing blocks.

Here is a quote from Apple documentation
Queues are not bound to any specific thread of execution and blocks submitted to independent queues may execute concurrently.

So this means if you have many queues that are under pressure, can cause your pingQueue to stop responding and executing blocks with delay.

Upvotes: 1

Related Questions