OSX 上的定期计时器回调 [英] Regular timer callbacks on OSX

查看:54
本文介绍了OSX 上的定期计时器回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 OSX 上每 N 毫秒(最好是 1 毫秒)进行一次回调.我已经设置了一个 CFRunLoop 然后像这样添加了一个计时器:

const double period = 0.001;CFAbsoluteTime 现在 = CFAbsoluteTimeGetCurrent();CFRunLoopTimerContext 上下文;std::memset(&context, 0, sizeof(context));context.info = ...;CFRunLoopTimerRef timerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, now + period, period, 0, 0, RunLoopTimerCallBack, &context);//将其添加到循环中.CFRunLoopAddTimer(/* 我的运行循环参考 */, timerRef, kCFRunLoopDefaultMode);

它似乎有效 - 我的 RunLoopTimerCallback() 大约每毫秒被调用一次.除非它没有.

我试过

这是我使用的代码:

#include #include #include 使用命名空间标准;void SetPriorityRealtime(){mach_timebase_info_data_t 时基;kern_return_t kr = mach_timebase_info(&timebase);如果 (kr != KERN_SUCCESS){cerr<<警告:无法获得时基."<<结束;返回;}//每个滴答的纳秒数是:cerr<<时基.数字<<"/" <<timebase.denom <<结束;//设置线程优先级.thread_time_constraint_policy ttcpolicy;thread_port_t threadport = pthread_mach_thread_np(pthread_self());//在刻度中.因此,将纳秒转换为滴答乘以 (timebase.denom/timebase.numer).ttcpolicy.period = 500 * 1000 * timebase.denom/timebase.numer;//我们要求调度的时间段.ttcpolicy.computation = 100 * 1000 * timebase.denom/timebase.numer;//我们必须运行的时间段中的最短时间.ttcpolicy.constraint = 100 * 1000 * timebase.denom/timebase.numer;//计算开始和结束之间的最长时间.ttcpolicy.preemptible = FALSE;kr = thread_policy_set(threadport, THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&ttcpolicy, THREAD_TIME_CONSTRAINT_POLICY_COUNT);如果 (kr != KERN_SUCCESS){cerr<<警告:无法设置线程策略:"<<kr<<结束;返回;}}

老实说,我仍然不完全确定 thread_time_constraint_policy 成员如何影响事情.但至少这表明这是可能的.现在在 Windows 上执行此操作...

I'm trying to get a callback every N milliseconds (ideally 1) on OSX. I've set up a CFRunLoop and then added a timer like so:

const double period = 0.001;

CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();

CFRunLoopTimerContext context;
std::memset(&context, 0, sizeof(context));
context.info = ...;

CFRunLoopTimerRef timerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, now + period, period, 0, 0, RunLoopTimerCallBack, &context);

// Add it to the loop.
CFRunLoopAddTimer(/* my run loop reference */, timerRef, kCFRunLoopDefaultMode);

It seems to work - my RunLoopTimerCallback() gets called approximately every millisecond. Except when it doesn't. The documentation for CFRunLoopTimerCreate says:

The fine precision (sub-millisecond at most) of the interval may be adjusted slightly by the timer if implementation reasons to do so exist.

So I expect it to more or less work, but in practice I get delays between callbacks of up to 8 ms:

I've tried setting the run loop thread to real-time priority but it didn't make any difference. Does anyone have any idea why I would be getting these delays? I realise this is pushing the OS quite hard and maybe it is some scheduling thing, but still... 1 millisecond isn't that short.

解决方案

Actually, I was being an idiot. Setting real-time thread priority makes a huge difference. Here is the result:

And here is the code I used:

#include <mach/mach_time.h>
#include <mach/thread_policy.h>

#include <iostream> 
using namespace std;

void SetPriorityRealtime()
{
    mach_timebase_info_data_t timebase;
    kern_return_t kr = mach_timebase_info(&timebase);
    if (kr != KERN_SUCCESS)
    {
        cerr << "Warning: Couldn't get timebase." << endl;
        return;
    }

    // The number of nanoseconds per tick is: 
    cerr << timebase.numer << " / " << timebase.denom << endl;

    // Set the thread priority.
    thread_time_constraint_policy ttcpolicy;
    thread_port_t threadport = pthread_mach_thread_np(pthread_self());

    // In ticks. Therefore to convert nanoseconds to ticks multiply by (timebase.denom / timebase.numer).
    ttcpolicy.period = 500 * 1000 * timebase.denom / timebase.numer; // Period over which we demand scheduling.
    ttcpolicy.computation = 100 * 1000 * timebase.denom / timebase.numer; // Minimum time in a period where we must be running.
    ttcpolicy.constraint = 100 * 1000 * timebase.denom / timebase.numer; // Maximum time between start and end of our computation in the period.
    ttcpolicy.preemptible = FALSE;

    kr = thread_policy_set(threadport, THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&ttcpolicy, THREAD_TIME_CONSTRAINT_POLICY_COUNT);
    if (kr != KERN_SUCCESS)
    {
        cerr << "Warning: Couldn't set thread policy: " << kr << endl;
        return;
    }
}

To be honest, I'm still not entirely sure how the thread_time_constraint_policy members affect things. But at least this shows it is possible. Now to do it on Windows...

这篇关于OSX 上的定期计时器回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆