简体   繁体   中英

Timing issue with dispatch_source_t handler function - am I following the right pattern for dispatch timer?

I read the documentation and came to know that timer (dispatch_source_t) skips to fire if the handler is still in progress for previous iterations.

But this whole business of handler taking it longer makes this inaccurate. And I am observing that I am unable to stop the timer at intended times.

My code looks like this:

 double secondsToFire = 1.0f;
 dispatch_queue_t queue = dispatch_get_main_queue();
 m_myTimer = CreateDispatchTimer(secondsToFire, queue,
^{       
    //Do some time consuming operation, taking any number of seconds
    int retVal = DoSomeOperation();

    if (retVal == 1)
    {
        cancelTimer(m_myTimer);
        SomeOtherOperation();            
    }
});

dispatch_source_t CreateDispatchTimer(double interval, dispatch_queue_t queue, dispatch_block_t block)
{
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    if (timer)
    {
     //   dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, interval * NSEC_PER_SEC), interval * NSEC_PER_SEC, (1ull * NSEC_PER_SEC) / 10);

        dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 0), interval * NSEC_PER_SEC, 0);
        dispatch_source_set_event_handler(timer, block);
        dispatch_resume(timer);
    }
    return timer;
}

void cancelTimer(dispatch_source_t _timer)
{
    if (_timer)
    {
        dispatch_source_cancel(_timer);
        _timer = nil;
    }
}

Note:

Inside DoSomeOperation() , I have code enclosed with @synchronized(array) , in which I access an array who is being written by another private queue. But entire DoSomeOperation() is executed on main queue.

My question is, is this is the right and accurate timing model? I am posting here because I am facing lot of inaccuracies - timer doesn't fire every second, and it doesn't stop as intended too. I am able to observe that SomeOtherOperation() gets called when retVal == 1 , but timer isn't done yet.

Another Note:

m_myTimer above is an iVar, and my project is ARC, if that could make any difference.

No, a dispatch timer doesn't get "skipped" if it fires while your handler is running, the handler will get re-invoked for the pending event right away once the previous invocation returns.

If multiple firings occur while the handler is running or enqueued (or while the source is suspended), they will get all get coalesced into a single handler invocation (as is the case for all edge-triggered source types).

You can check how many firings a given handler invocation is for with dispatch_source_get_data()

My concern was about accuracy in starting, firing and stopping, and not in correct reporting of things.

I finally ended up assigning one of my tasks off a private queue instead of main one. The advantage could be clearly visible in timer accuracy and prompt timer cancellation.

Conclusion:

More the same (esp. main) queue getting flogged by timer tasks, more they become inaccurate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM