2017-06-01 4 views
0

J'essaie d'obtenir un rappel toutes les N millisecondes (idéalement 1) sur OSX. J'ai mis en place un CFRunLoop puis ajouté une minuterie comme ceci:Rappels de minuterie réguliers sur 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); 

Il semble fonctionner - mon RunLoopTimerCallback() est appelé à peu près toutes les millisecondes. Sauf quand ce n'est pas le cas. Le documentation for CFRunLoopTimerCreate dit:

La précision fine (sous-milliseconde au plus) de l'intervalle peut être légèrement ajustée par la minuterie si des raisons de mise en œuvre pour y parvenir existent.

donc je pense que cela fonctionne plus ou moins, mais dans la pratique je reçois des retards entre callbacks jusqu'à 8 ms:

delay graph

J'ai essayé setting the run loop thread to real-time priority mais il n'a pas fait toute différence. Est-ce que quelqu'un a une idée de la raison pour laquelle j'aurais ces retards? Je me rends compte que cela pousse l'OS assez dur et peut-être que c'est quelque chose de planification, mais quand même ... 1 milliseconde n'est pas que court.

Répondre

0

En fait, j'étais un idiot. La définition de la priorité des threads en temps réel fait une énorme différence. Voici le résultat:

millisecond!

Et voici le code je:

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

Pour être honnête, je ne suis toujours pas tout à fait sûr de savoir comment les membres thread_time_constraint_policy affectent les choses. Mais au moins cela montre que c'est possible. Maintenant, pour le faire sur Windows ...