Dormir por una duración exacta

Mi comprensión de la función Sleep es que sigue “al menos semántica”, es decir, sleep (5) garantizará que el hilo duerma durante 5 segundos, pero puede permanecer bloqueado durante más de 5 segundos dependiendo de otros factores. ¿Hay una manera de dormir exactamente durante un período de tiempo específico (sin esperar ocupado).

Como han dicho otros, realmente necesitas usar un sistema operativo en tiempo real para intentar lograrlo. La sincronización precisa del software es bastante complicada.

Sin embargo … aunque no es perfecto, puede obtener MUCHO mejores resultados que “normales” simplemente aumentando la prioridad del proceso que necesita una mejor sincronización . En Windows puedes lograr esto con la función SetPriorityClass . Si establece la prioridad en el nivel más alto ( REALTIME_PRIORITY_CLASS: 0x00000100 ) obtendrá resultados de temporización mucho mejores. De nuevo, esto no será perfecto como lo que estás pidiendo, sin embargo.

Es probable que esto también sea posible en otras plataformas que no sean Windows, pero nunca tuve motivos para hacerlo, así que no lo he probado.

EDITAR: De acuerdo con el comentario de Andy T, si su aplicación tiene múltiples subprocesos, también debe tener cuidado con la prioridad asignada a los subprocesos. Para Windows esto está documentado aquí .


Algunos antecedentes …

Hace un tiempo, utilicé SetPriorityClass para boost la prioridad en una aplicación en la que estaba haciendo un análisis en tiempo real de video de alta velocidad y NO podía faltar un fotogtwig. Los marcos llegaban a la PC a una frecuencia muy regular (controlada por HW de framegrabber externo) de 300 cuadros por segundo (fps), lo que provocó una interrupción de HW en cada cuadro que luego revisé. Dado que el tiempo era muy importante, recopilé muchas estadísticas sobre el tiempo de interrupción (utilizando el material QueryPerformanceCounter ) para ver qué tan grave era la situación, y quedé horrorizado por las distribuciones resultantes. No tengo las estadísticas a la mano, pero básicamente, Windows daba servicio a la interrupción cuando parecía que funcionaba con la prioridad normal. Los histogtwigs eran muy desordenados, con el stdev más ancho que mi período de ~ 3ms. ¡Con frecuencia tendría brechas gigantescas de 200 ms o más en el servicio de interrupción (recuerde que la interrupción se disparó aproximadamente cada 3 ms)! Es decir: ¡Las interrupciones de HW están lejos de ser exactas! Estás atascado con lo que el sistema operativo decide hacer por ti.

Sin embargo, cuando descubrí la configuración REALTIME_PRIORITY_CLASS y la evalué con esa prioridad, fue significativamente mejor y la distribución del intervalo de servicio fue extremadamente estrecha. Podía correr 10 minutos de 300 fps y no perder un solo cuadro. Los períodos de servicio de interrupción medidos fueron más o menos exactamente 1/300 s con una distribución estrecha.

Además, intente minimizar las otras cosas que el sistema operativo está haciendo para ayudar a mejorar las probabilidades de que su tiempo funcione mejor en la aplicación donde sea importante. por ejemplo: ¡no se realiza ninguna transencoding de video de fondo ni desfragmentación del disco ni nada mientras intenta obtener una sincronización precisa con otro código!

En resumen:

  1. Si realmente necesitas esto, ve con un sistema operativo en tiempo real
  2. Si no puede usar un sistema operativo en tiempo real (imposible o impráctico), boost la prioridad de su proceso probablemente mejorará mucho su tiempo, como lo hizo para mí.
  3. Las interrupciones de HW no lo harán … ¡el sistema operativo todavía tiene que decidir darles servicio!
  4. Asegúrese de no tener muchos otros procesos en ejecución que compitan por la atención del sistema operativo
  5. Si el tiempo es realmente importante para ti, haz algunas pruebas. Aunque hacer que el código se ejecute exactamente cuando lo desea no es muy fácil, medir esta desviación es bastante fácil. Los contadores de alto rendimiento en PC (lo que se obtiene con QueryPerformanceCounter) son extremadamente buenos.

Ya que puede ser útil (aunque un poco fuera del tema), aquí hay una pequeña clase que escribí hace mucho tiempo para usar los contadores de alto rendimiento en una máquina con Windows. Puede ser útil para su prueba:

CHiResTimer.h

 #pragma once #include "stdafx.h" #include  class CHiResTimer { private: LARGE_INTEGER frequency; LARGE_INTEGER startCounts; double ConvertCountsToSeconds(LONGLONG Counts); public: CHiResTimer(); // constructor void ResetTimer(void); double GetElapsedTime_s(void); }; 

CHiResTimer.cpp

 #include "stdafx.h" #include "CHiResTimer.h" double CHiResTimer::ConvertCountsToSeconds(LONGLONG Counts) { return ((double)Counts / (double)frequency.QuadPart) ; } CHiResTimer::CHiResTimer() { QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&startCounts); // starts the timer right away } void CHiResTimer::ResetTimer() { QueryPerformanceCounter(&startCounts); // reset the reference counter } double CHiResTimer::GetElapsedTime_s() { LARGE_INTEGER countsNow; QueryPerformanceCounter(&countsNow); return ConvertCountsToSeconds(countsNow.QuadPart - startCounts.QuadPart); } 

No.

La razón por la que es “al menos semántica” es porque después de esos 5 segundos, otro hilo puede estar ocupado.

Cada hilo recibe un intervalo de tiempo del sistema operativo. El sistema operativo controla el orden en que se ejecutan los hilos.

Cuando pone un hilo en suspensión, el sistema operativo lo pone en una lista de espera, y cuando el temporizador finaliza, el sistema operativo “despierta” el hilo.
Esto significa que el hilo se agrega de nuevo a la lista de hilos activos, pero no se garantiza que se agregará en primer lugar. (¿Qué sucede si es necesario despertar 100 hilos en ese segundo específico? ¿Quién irá primero?)

Si bien Linux estándar no es un sistema operativo en tiempo real, los desarrolladores del kernel prestan mucha atención a cuánto tiempo permanecerá muerto el proceso de alta prioridad mientras se mantienen los lockings del kernel. Por lo tanto, un kernel de Linux común suele ser lo suficientemente bueno para muchas aplicaciones en tiempo real.

Puede progtwigr su proceso como una tarea en tiempo real con la sched_setscheduler(2) , utilizando SCHED_FIFO o SCHED_RR . Los dos tienen pequeñas diferencias en la semántica, pero puede ser suficiente saber que una tarea SCHED_RR finalmente SCHED_RR el procesador a otra tarea de la misma prioridad debido a segmentos de tiempo, mientras que una tarea SCHED_FIFO solo SCHED_FIFO la CPU a otra tarea del la misma prioridad debido al locking de E / S o una llamada explícita a sched_yield(2) .

Tenga cuidado al usar tareas progtwigdas en tiempo real; Como siempre tienen prioridad sobre las tareas estándar, puedes encontrarte fácilmente codificando un bucle infinito que nunca abandona la CPU y evita que los administradores usen ssh para detener el proceso. Por lo tanto, puede que no esté mal ejecutar un sshd con una mayor prioridad en tiempo real, al menos hasta que esté seguro de haber solucionado los errores más graves.

Existen variantes de Linux disponibles que se han trabajado para proporcionar garantías en tiempo real. RTLinux tiene soporte comercial ; Xenomai y RTAI son implementaciones competitivas de extensiones en tiempo real para Linux, pero no sé nada más sobre ellas.

Como dijeron los que respondieron anteriormente: no hay forma de ser exactos (algunas interrupciones de hardware o en el tiempo real sugeridas, e incluso esas no son exactas ). Creo que lo que está buscando es algo más preciso que la función sleep () y encontrará que, dependiendo de su sistema operativo, en, por ejemplo, la función Windows Sleep () o bajo GNU, la función nanosleep ().

http://msdn.microsoft.com/en-us/library/ms686298%28VS.85%29.aspx

http://www.delorie.com/gnu/docs/glibc/libc_445.html

Ambos te darán precisión en unos pocos milisegundos.

Bueno, intenta abordar un problema difícil, y lograr el tiempo exacto no es factible: lo mejor que puede hacer es usar interrupciones de hardware , y la implementación dependerá de su hardware subyacente y su sistema operativo (es decir, que necesitará un sistema operativo en tiempo real , que no es el sistema operativo de escritorio más común). ¿Cuál es tu plataforma de destino exacta?

No. Porque siempre depende del sistema operativo para manejar los hilos de activación en el momento adecuado.

No hay manera de dormir durante un período de tiempo específico utilizando el estándar C. Necesitará, como mínimo, una biblioteca de terceros que ofrezca una mayor granularidad, y es posible que también necesite un kernel de sistema operativo especial, como los kernels de Linux en tiempo real.

Por ejemplo, aquí hay una discusión de lo cerca que puede llegar a los sistemas Win32 .

Esta no es una pregunta C.