2017-06-01 2 views
0

Ich versuche, einen Rückruf alle N Millisekunden (idealerweise 1) auf OSX. Ich habe ein CFRunLoop und dann hinzugefügt, um eine Timer wie so ein:Regelmäßige Timer-Callbacks auf OSX

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

Es scheint zu funktionieren - mein RunLoopTimerCallback() wird etwa jede Millisekunde genannt. Außer wenn es nicht so ist. Die documentation for CFRunLoopTimerCreate sagt:

Die feine Präzision (Sub-Millisekunden höchstens) des Intervalls durch den Timer leicht eingestellt werden können, wenn die Umsetzung Gründe, dies zu existieren.

So erwarte ich, dass es mehr oder weniger Arbeit, aber in der Praxis ich Verzögerungen zwischen Rückrufen von bis zu 8 ms:

delay graph

Ich habe versucht setting the run loop thread to real-time priority aber es hat nicht machen jede Differenz. Hat jemand eine Idee, warum ich diese Verzögerungen bekommen würde? Ich realisiere, dass dies das Betriebssystem ziemlich hart treibt und vielleicht ist es etwas Planung, aber immer noch ... 1 Millisekunde ist nicht , dass kurz.

Antwort

0

Eigentlich war ich ein Idiot. Das Festlegen der Echtzeit-Thread-Priorität macht einen großen Unterschied. Hier ist das Ergebnis:

millisecond!

Und hier ist der Code, den ich verwenden:

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

Um ehrlich zu sein, ich bin noch nicht ganz sicher, wie die thread_time_constraint_policy Mitglieder Dinge beeinflussen. Aber zumindest zeigt dies, dass es möglich ist. Jetzt unter Windows ...