2011-03-06 12 views
7

Mi comprensión de la función Sleep es que sigue "al menos la 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 alguna forma de dormir exactamente durante un período de tiempo específico (sin esperar demasiado ocupado)?Dormir por una duración exacta

+4

http://en.wikipedia.org/wiki/Real-time_operating_system –

+2

"sin esperar ocupado" <- ni siquiera puede hacerlo con la espera ocupada. Su hilo puede ser interrumpido mientras espera. (Quizás alguna prioridad de Windows en tiempo real podría ser útil) –

+4

Defina "exacto". Incluso con un ensamblador codificado a mano conectado a una interrupción de hardware, usted tendrá efectos debido a errores de caché e incluso esperando a que la tubería de instrucciones se borre y rellene. Incluso con el bucle ocupado, estarás apagado microsegundos. ¿Qué es "exacto"? –

Respuesta

14

Como han dicho otros, realmente necesita utilizar un sistema operativo en tiempo real para intentarlo. La sincronización precisa del software es bastante complicada.

Sin embargo ... aunque no es perfecto, puede obtener MUCHO mejores resultados que "normal" simplemente aumentando la prioridad del proceso que necesita un mejor tiempo. En Windows puede lograr esto con la función SetPriorityClass.Si establece la prioridad en el nivel más alto (REALTIME_PRIORITY_CLASS: 0x00000100) obtendrá mucho mejores resultados de temporización. Nuevamente, aunque esto no será perfecto como lo está pidiendo.

Esto también es posible en otras plataformas además de Windows, pero nunca tuve razones para hacerlo, así que no lo he probado.

EDITAR: Según el comentario de Andy T, si su aplicación es de subprocesos múltiples también debe tener cuidado con la prioridad asignada a los hilos. Para Windows esto está documentado here.


Algunos antecedentes ...

Hace un tiempo yo solía SetPriorityClass para aumentar la prioridad de una aplicación en la que estaba haciendo análisis en tiempo real de vídeo de alta velocidad y no podía faltar un marco. Los marcos llegaban a la PC a muy frecuencia (impulsada por framegrabber externo HW) de 300 fotogramas por segundo (fps), que disparaba una interrupción HW en cada fotograma que luego revisaba. Como el tiempo era muy importante, recopilé muchas estadísticas sobre el tiempo de interrupción (usando QueryPerformanceCounter cosas) para ver cuán mala era en realidad la situación, y quedé horrorizada con las distribuciones resultantes. No tengo las estadísticas a mano, pero básicamente Windows estaba atendiendo la interrupción siempre que se sentía así cuando se ejecutaba con una prioridad normal. Los histogramas fueron muy desordenados, con el stdev siendo más ancho que mi período ~ 3ms. Con frecuencia tendría espacios gigantescos de 200 ms o más en el servicio de interrupción (recuerde que la interrupción se activó cada 3 ms). es decir: ¡las interrupciones de HW están LEJOS de exactas! Estás atrapado con lo que el sistema operativo decide hacer por ti.

Sin embargo, cuando descubrí la configuración REALTIME_PRIORITY_CLASS y se hizo una evaluación comparativa con esa prioridad, fue significativamente significativamente y la distribución del intervalo de servicio fue extremadamente estrecha. Podría correr 10 minutos de 300 fps y no perder un solo cuadro. Los períodos medidos de servicio de interrupción fueron exactamente 1/300 s con una distribución ajustada.

Además, intente y minimice 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 hay transcodificación de video en el fondo, ni desengrase del disco, ni nada mientras intentas obtener un timing de precisión con otro código.

En resumen:

  1. Si realmente necesita esto, ir con un sistema operativo de tiempo real
  2. Si no puede utilizar un sistema operativo en tiempo real (imposible o poco práctico), aumentando su prioridad proceso Probablemente mejore mucho su tiempo, como lo hizo para mí
  3. Las interrupciones de HW no lo harán ... ¡el sistema operativo aún debe 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 usted, realice algunas pruebas. Aunque obtener código para ejecutar exactamente cuando lo desee no es muy fácil, medir esta desviación es bastante fácil. Los contadores de alto rendimiento en PC (lo que obtienes con QueryPerformanceCounter) son extremadamente buenos.

Dado que puede ser útil (aunque un poco fuera de 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 <windows.h> 

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); 
} 
+2

historia impresionante y un montón de código proporcionado también :) lástima que solo tengo +1 para dar. – sarnold

+0

y si el programa es multiproceso, debe especificar una prioridad alta para el hilo que duerme demasiado –

+0

@AndyT - Buen punto, lo actualizaré. ¡Gracias! – Russ

0

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

2

Bueno, intenta hacer frente a un problema difícil, y lograr exacta momento no es factible: lo mejor que puede hacer es utilizar hardware interrupts, y la puesta en práctica dependerá tanto de su hardware subyacente, y su funcionamiento sistema (es decir, necesitará a real-time operating system, que la mayoría de los sistemas operativos de escritorio normales no tienen). ¿Cuál es su plataforma objetivo exacta?

5

La razón es "por lo menos la semántica" se debe a que después de esos 5 segundos algún otro flujo puede estar ocupado.

Cada hilo recibe una porción de tiempo del sistema operativo. El sistema operativo controla el orden en que se ejecutan los hilos.

Cuando pone un hilo a dormir, el sistema operativo pone el hilo en una lista de espera, y cuando el temporizador termina 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 t se agregará en primer lugar. (¿Qué pasa si 100 hilos deben ser despertados en ese segundo específico? ¿Quién irá primero?)

2

Como contestadores anteriores dijeron: no hay forma de ser exacto (algunos sugirieron en tiempo real-OS o interrupciones de hardware e incluso esos no son exacta). Creo que lo que estás buscando es algo que es más preciso que la función sleep() y lo encuentras dependiendo de tu 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 le proporciona una precisión dentro de unos pocos milisegundos.

+0

+1 - Incluso los RTOS no son capaces de lograr eso. – mouviciel

0

No hay forma de que duerma durante un período de tiempo especificado utilizando la C. estándar Necesitará, como mínimo, una biblioteca de terceros que proporcione una mayor granularidad, y también podría necesitar un kernel de sistema operativo especial como el real- tiempo de kernels de Linux.

Por ejemplo, aquí hay un discussion of how close you can come on Win32 systems.

Esta no es una pregunta en C.

4

Mientras estándar de Linux no es un sistema operativo en tiempo real, los desarrolladores del kernel pagan atención cercana a cuánto tiempo un proceso de alta prioridad se mantendría muerto mientras se mantienen los bloqueos del núcleo. Por lo tanto, un núcleo de stock de Linux suele ser lo suficientemente bueno para muchas aplicaciones en tiempo real.

Puede programar su proceso como una tarea en tiempo real con la llamada sched_setscheduler(2), usando SCHED_FIFO o SCHED_RR. Los dos tienen ligeras diferencias en semántica, pero puede ser suficiente saber que una tarea SCHED_RR eventualmente abandonará el procesador a otra tarea de la misma prioridad debido a cortes de tiempo, mientras que una tarea SCHED_FIFO solo abandonará la CPU a otra tarea del misma prioridad debido al bloqueo de E/S o una llamada explícita a sched_yield(2).

Tenga cuidado al usar tareas programadas en tiempo real; como siempre tienen prioridad sobre las tareas estándar, puede encontrar fácilmente la codificación de un bucle infinito que nunca renuncia a la CPU y bloquea a los administradores de usar ssh para matar el proceso. Por lo tanto, no estaría de más ejecutar un sshd con una mayor prioridad en tiempo real, al menos hasta que esté seguro de haber solucionado los peores errores.

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

+0

+1 por mencionar el soporte en Linux – fayyazkl

Cuestiones relacionadas