.net - segundos - tiempos en c++
Obtener tics precisos de un temporizador en C# (6)
Estoy intentando reconstruir una aplicación antigua de metrónomo que se escribió originalmente usando MFC en C ++ para que se escriba en .NET usando C #. Uno de los problemas con los que me estoy metiendo es conseguir que el temporizador "marque" con la precisión suficiente.
Por ejemplo, suponiendo un BPM (latidos por minuto) fácil de 120, el temporizador debe marcar cada 0,5 segundos (o 500 milisegundos). El uso de esto como base para los tics, sin embargo, no es del todo exacto, ya que .NET solo garantiza que su temporizador no marque antes de que haya transcurrido el tiempo transcurrido.
Actualmente, para solucionar este problema con el mismo ejemplo de 120 BPM utilizado anteriormente, estoy configurando los ticks en algo así como 100 milisegundos y solo estoy reproduciendo el clic en cada 5 tic del temporizador. Esto mejora bastante la precisión, pero si se siente como un truco.
Entonces, ¿cuál es la mejor manera de obtener tics precisos? Sé que hay más temporizadores disponibles que el temporizador de formularios de Windows que está disponible en Visual Studio, pero no estoy realmente familiarizado con ellos.
¿Qué está usando la aplicación C ++? Siempre puede usar lo mismo o ajustar el código del temporizador de C ++ en una clase C ++ / CLI.
Hay tres clases de temporizador llamadas ''Timer'' en .NET. Parece que está utilizando el formulario de Windows Forms, pero en realidad puede que le resulte más útil la clase System.Threading.Timer, pero tenga cuidado porque devuelve la llamada a un hilo del grupo, por lo que no puede interactuar directamente con su formulario desde la devolución de llamada.
Otro enfoque podría ser p / invoke a los temporizadores multimedia Win32 - timeGetTime, timeSetPeriod, etc.
Un Google rápido encontró esto, que podría ser útil http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx
''Multimedia'' (temporizador) es la palabra de moda que debe buscarse en este contexto.
He tenido este problema al desarrollar un proyecto reciente de registro de datos. El problema con los temporizadores .NET (windows.forms, system.threading y system.timer) es que solo tienen una precisión de hasta 10 milisegundos, lo que se debe a la programación del evento incorporada en .NET, creo. (Estoy hablando de .NET 2 aquí). Esto no era aceptable para mí, así que tuve que usar el temporizador multimedia (debe importar el dll). También escribí una clase contenedora para todos los temporizadores y así puede cambiar entre ellos si es necesario usando cambios mínimos de código. Echa un vistazo a la publicación de mi blog aquí: http://www.indigo79.net/archives/27
Las clases de temporizador pueden comenzar a comportarse de manera extraña cuando el código del evento ''tic'' del temporizador no se termina de ejecutar en el momento en que se produce el siguiente ''tic''. Una forma de combatir esto es desactivar el temporizador al comienzo del evento tick, luego volver a habilitarlo al final.
Sin embargo, este enfoque no es adecuado en los casos en que el tiempo de ejecución del código ''tic'' no es un error aceptable en el tiempo del tic, ya que el temporizador se desactivará (sin contar) durante ese tiempo.
Si deshabilitar el temporizador es una opción, también puede lograr el mismo efecto creando un hilo separado que se ejecute, duerma durante x milisegundos, se ejecute, duerma, etc.
Otra posibilidad es que haya un error en la implementación de WPF de DispatcherTimer (hay una falta de coincidencia entre milisegundos y ticks que causa una posible imprecisión dependiendo del tiempo exacto de ejecución del proceso), como se evidencia a continuación:
class DispatcherTimer
{
public TimeSpan Interval
{
set
{
...
_interval = value;
// Notice below bug: ticks1 + milliseconds [Bug1]
_dueTimeInTicks = Environment.TickCount + (int)_interval.TotalMilliseconds;
}
}
}
http://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/Dispatcher.cs
class Dispatcher
{
private object UpdateWin32TimerFromDispatcherThread(object unused)
{
...
_dueTimeInTicks = timer._dueTimeInTicks;
SetWin32Timer(_dueTimeInTicks);
}
private void SetWin32Timer(int dueTimeInTicks)
{
...
// Notice below bug: (ticks1 + milliseconds) - ticks2 [Bug2 - almost cancels Bug1, delta is mostly milliseconds not ticks]
int delta = dueTimeInTicks - Environment.TickCount;
SafeNativeMethods.SetTimer(
new HandleRef(this, _window.Value.Handle),
TIMERID_TIMERS,
delta); // <-- [Bug3 - if delta is ticks, it should be divided by TimeSpan.TicksPerMillisecond = 10000]
}
}
http://referencesource.microsoft.com/#WindowsBase/Shared/MS/Win32/SafeNativeMethodsCLR.cs,505
class SafeNativeMethodsPrivate
{
...
[DllImport(ExternDll.User32, SetLastError = true, ExactSpelling=true, CharSet=System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr SetTimer(HandleRef hWnd, int nIDEvent, int uElapse, NativeMethods.TimerProc lpTimerFunc);
}
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906%28v=vs.85%29.aspx
uElapse [in]
Type: UINT
The time-out value, in milliseconds. // <-- milliseconds were needed eventually
System.Windows.Forms.Timer
está limitado a una precisión de 55 milisegundos ...