OSX 上的定期计时器回调 [英] Regular timer callbacks on 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屋!