2014-10-10 62 views
0

我阅读了文档,发现如果处理程序仍在进行之前的迭代,则定时器(dispatch_source_t)将跳过触发。dispatch_source_t处理函数的时序问题 - 我是否遵循调度计时器的正确模式?

但是,处理器的整个业务需要更长的时间,这使得这个不准确。而且我正在观察,我无法在预定的时间停止计时器。

我的代码如下所示:

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

注:

里面DoSomeOperation(),我有附带@synchronized(array),在我访问谁是被另一个私人队列写的阵列码。但是整个DoSomeOperation()在主队列上执行。

我的问题是,这是正确和准确的时间模型?我在这里发帖是因为我面临着很多不准确的情况 - 计时器不会每秒都会触发,而且它也不会像预期的那样停止。我能够观察到SomeOtherOperation()retVal == 1时被调用,但是定时器尚未完成。

另注:

m_myTimer以上是伊娃,我的项目是ARC,如果能够有任何区别。

+0

有没有原因你不使用重复'NSTimer'? – 2014-10-10 19:18:57

+0

我想要更精确 - 与GCD源相比,NSTimers不是很准确。 – 2014-10-10 19:19:54

回答

0

我关心的是关于首发的准确性,在两不误报告射击和停止,而不是。

我终于把我的一个任务从私有队列中分配出来,而不是从主队列中分配出来。在定时器精度和提示定时器取消时,优势可以清晰可见。

结论:

更多相同(ESP主)队列中获取由定时器任务鞭打,他们越不准确。

2

不,调度计时器如果在处理程序正在运行时触发,则不会“跳过”,一旦前一次调用返回,处理程序将立即重新调用该未决事件。

如果在处理程序正在运行或排队(或源被挂起时)时发生多次触发,它们将全部获取合并到单个处理程序调用中(如所有边缘触发源类型的情况)。

您可以检查一个给定的处理程序调用多少点火是与dispatch_source_get_data()

+0

谢谢,我知道这一点,我已经在使用它。问题是 - 有没有办法预防这种情况?另外,取消定时器呢? – 2014-10-11 05:29:52

+0

阻止合并?没有,抱歉(但你可以明显地发现它,并忽略额外的发射)。 调用'dispatch_source_cancel'将会在函数返回后立即阻止处理程序的将来调用,同样会使用'dispatch_source_set_timer'改变定时器参数(例如将下一次着火时间设置为永久) – das 2014-10-12 23:54:47