문제

원래 C#을 사용하여 .NET에서 작성하기 위해 C++에서 MFC를 사용하여 작성된 이전 메트로놈 응용 프로그램을 다시 작성하려고 합니다.내가 겪고 있는 문제 중 하나는 타이머가 충분히 정확하게 "똑딱"하도록 하는 것입니다.

예를 들어, 쉬운 BPM(분당 비트 수)이 120이라고 가정하면 타이머는 0.5초(또는 500밀리초)마다 작동해야 합니다.그러나 이를 틱의 기초로 사용하는 것은 완전히 정확하지 않습니다. .NET에서는 경과 시간이 경과하기 전에 타이머가 틱되지 않는다는 것만 보장하기 때문입니다.

현재 위에서 사용된 동일한 120BPM 예제에서 이 문제를 해결하기 위해 틱을 100밀리초 정도로 설정하고 5번째 타이머 틱마다 클릭 사운드만 재생합니다.이렇게 하면 정확도가 상당히 향상되지만 약간의 해킹처럼 느껴질 수도 있습니다.

그렇다면 정확한 진드기를 얻는 가장 좋은 방법은 무엇입니까?Visual Studio에서 쉽게 사용할 수 있는 Windows 양식 타이머보다 더 많은 타이머를 사용할 수 있다는 것을 알고 있지만 실제로는 익숙하지 않습니다.

도움이 되었습니까?

해결책

.NET에는 'Timer'라는 세 가지 타이머 클래스가 있습니다.Windows Forms를 사용하고 있는 것처럼 들리지만 실제로는 System.Threading.Timer 클래스가 더 유용할 수 있습니다. 하지만 이 클래스는 풀 스레드에서 다시 호출하므로 주의해야 합니다. 따라서 다음에서 양식과 직접 상호 작용할 수 없습니다. 콜백.

또 다른 접근 방식은 Win32 멀티미디어 타이머(timeGetTime, timeSetPeriod 등)를 p/invoke하는 것입니다.

빠른 Google에서 이것을 찾았습니다. 유용할 수 있습니다. http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx

이런 맥락에서 검색해야 할 유행어는 '멀티미디어'(타이머)입니다.

다른 팁

C++ 애플리케이션은 무엇을 사용하고 있나요?언제든지 동일한 것을 사용하거나 C++의 타이머 코드를 C++/CLI 클래스로 래핑할 수 있습니다.

최근 데이터 로깅 프로젝트를 개발할 때 이런 문제가 발생했습니다..NET 타이머(windows.forms, system.threading 및 system.timer)의 문제점은 .NET에 내장된 이벤트 스케줄링으로 인해 약 10밀리초까지만 정확하다는 것입니다.(여기서는 .NET 2에 대해 이야기하고 있습니다).이것은 나에게 허용되지 않았으므로 멀티미디어 타이머를 사용해야 했습니다(dll을 가져와야 함).또한 모든 타이머에 대한 래퍼 클래스를 작성했기 때문에 필요한 경우 최소한의 코드 변경을 통해 타이머 간에 전환할 수 있습니다.여기에서 내 블로그 게시물을 확인하세요.http://www.indigo79.net/archives/27

또 다른 가능성은 Dispatchertimer의 WPF 구현에 버그가있을 것입니다 (정확한 프로세스 실행 시간에 따라 정확한 부정확성을 유발하는 밀리 초과 진드기 사이에 불일치가 발생 함).

http://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/DispatcherTimer.cs,143

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

다음 '틱'이 발생할 때까지 타이머 '틱' 이벤트 코드의 실행이 완료되지 않으면 타이머 클래스가 이상하게 동작하기 시작할 수 있습니다.이 문제를 해결하는 한 가지 방법은 틱 이벤트 시작 시 타이머를 비활성화한 다음 마지막에 다시 활성화하는 것입니다.

그러나 이 접근 방식은 '틱' 코드의 실행 시간이 틱 타이밍 오류를 허용할 수 없는 경우에는 적합하지 않습니다. 해당 시간 동안 타이머가 비활성화(계산되지 않음)되기 때문입니다.

타이머를 비활성화하는 것이 옵션인 경우 실행, x 밀리초 동안 휴면, 실행, 휴면 등을 수행하는 별도의 스레드를 생성하여 동일한 효과를 얻을 수도 있습니다.

System.Windows.Forms.Timer 정확도는 55밀리초로 제한됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top