2

I have a timer in c# to execute a thread every 10ms:

        private void setTimers(IntPtr paramA, List<int> paramB)
    {
        varTimer= new System.Timers.Timer();
        varTimer.Elapsed += delegate { Check(paramA, paramB); };
        varTimer.Interval = 10;
        varTimer.Start();
    }

And the function:

private void Check(IntPtr paramA, List<int> paramB)
    {
            try
            {
                acquiredLock= false;

                System.Threading.Monitor.TryEnter(syncThreadsC, ref acquiredLock);
                if (acquiredLock)
                {
                    // logic
                }
                else
                {
                    return;
                }
            }
            finally
            {
                if (acquiredLock)
                    System.Threading.Monitor.Exit(syncThreadsC);
            }

    }

I'm asking it to be launched every 10ms and even knowing that it won't be superprecise, I get these numbers if I check with StopWatch when I enter and exit Check:

[605] [668] [693] [755] [785] [847] [878] [941] [971] [40] [67] [128] [159]

The logic of Check takes between 1 and 2 ms only. I'm wondering, as I believe there is nothing more precise in c#, if there's anything in c++ to launch a timer every X ms with higher precision. If so, I will do it in an external dll and call it. These numbers are too off for what I need.

Thanks

сами J.D.
  • 483
  • 2
  • 5
  • 19
  • See the post I mentioned above. That timer will give you very high accuracy, and you won't have to make your own library to use it - just a little P/Invoke to winmm.dll. I use it in a project of my own - works great. – dodexahedron Aug 12 '15 at 02:03
  • Do you have any sample code to see how to call MyFunction() every few ms? Thanks. BTW, MS says now we should use CreateTimerQueueTimer: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682485(v=vs.85).aspx :) Thanks – сами J.D. Aug 12 '15 at 02:35
  • 1
    Check the answer I just posted, for sample code. Also, A TimerQueueTimer is exactly what the .Net Timer class already wraps, so using PInvoke for one of those is pointless. Note that normal timers in .Net are only going to give you around 15ms of precision, and anything better than that is more or less luck. – dodexahedron Aug 12 '15 at 03:14
  • 1
    @dodexahedron: Actually, although the .NET `Timer` class appears to wrap the `TimerQueueTimer` (maybe, it's kind of hard to tell), it restricts things to 15 ms resolution (usually). You *can* get close to 1 ms accuracy using the `TimerQueueTimer` if you create your own wrapper for it. See my article https://www.informit.com/guides/content.aspx?g=dotnet&seqNum=817 – Jim Mischel Aug 12 '15 at 03:35

1 Answers1

1

Using a corrected timer class from Raise event in high resolution interval/timer, here is an example implementation of a high-resolution timer:

class Program
{
    public void Main(string[] args)
    {
        uint timerId = SafeNativeMethods.timeSetEvent( 1, 1, HandleTimerTick, UIntPtr.Zero, 1 );
        Console.ReadLine();
        SafeNativeMethods.timeKillEvent( timerId );
    }

    public static void HandleTimerTick( uint id, uint msg, UIntPtr userCtx, UIntPtr uIntPtr, UIntPtr intPtr )
    {
        Console.WriteLine( "This is a bad idea on short timescales" );
    }
}

public static class SafeNativeMethods
{
    /// <summary>
    /// A timer event handler
    /// </summary>
    /// <param name="id">Timer identifier, as returned by the timeSetEvent function.</param>
    /// <param name="msg">Reserved</param>
    /// <param name="userCtx">The value that was passed in to the userCtx value of the timeSetEvent function.</param>
    /// <param name="dw1">Reserved</param>
    /// <param name="dw2">Reserved</param>
    public delegate void TimerEventHandler( UInt32 id, UInt32 msg, UIntPtr userCtx, UIntPtr dw1, UIntPtr dw2 );
    /// <summary>
    /// A multi media timer with millisecond precision
    /// </summary>
    /// <param name="msDelay">One event every msDelay milliseconds</param>
    /// <param name="msResolution">Timer precision indication (lower value is more precise but resource unfriendly)</param>
    /// <param name="handler">delegate to start</param>
    /// <param name="userCtx">callBack data </param>
    /// <param name="eventType">one event or multiple events</param>
    /// <remarks>Dont forget to call timeKillEvent!</remarks>
    /// <returns>0 on failure or any other value as a timer id to use for timeKillEvent</returns>
    [DllImport( "winmm.dll", SetLastError = true, EntryPoint = "timeSetEvent" )]
    public static extern UInt32 timeSetEvent( UInt32 msDelay, UInt32 msResolution, TimerEventHandler handler, UIntPtr userCtx, UInt32 eventType );

    /// <summary>
    /// The multi media timer stop function
    /// </summary>
    /// <param name="uTimerID">timer id from timeSetEvent</param>
    /// <remarks>This function stops the timer</remarks>
    [DllImport( "winmm.dll", SetLastError = true )]
    public static extern void timeKillEvent( UInt32 uTimerID );
}

Please be sure to kill your timer cleanly, using timeKillEvent, when you are done with it, and PLEASE don't use a ton of these timers in your application. They are resource-intensive.

Community
  • 1
  • 1
dodexahedron
  • 4,584
  • 1
  • 25
  • 37
  • Documentation strongly suggests that you not use the multimedia timers. As you say, they are highly resource intensive. The TimerQueueTimers are just as accurate and less resource intensive. – Jim Mischel Aug 12 '15 at 03:37
  • The reference source would suggest that System.Threading.Timer is built on top of TimerQueueTimer, especially since they even call it a TimerQueueTimer behind the scenes. See http://referencesource.microsoft.com/#mscorlib/system/threading/timer.cs,051a39d380760b26 . Note it is backed by a TimerHolder, which is, in turn, backed by a TimerQueueTimer. Whether or not that is backed by a win32 TimerQueueTimer is up to the implementation of the VM, but I'd wager Microsoft used their existing libraries for that one. Of course, I have no proof, without the .net VM source. Just seems likely. :) – dodexahedron Aug 12 '15 at 03:59
  • As a meta-comment, your article spurred me to do that research in the first place, so I learned a bunch from this. Thanks for the article. – dodexahedron Aug 12 '15 at 04:01
  • That source doesn't indicate where the ~15ms resolution is coming from, so I'm still baffled by that. Must be in the VM implementation. Have you tried it on Mono to see if the same behavior exists? – dodexahedron Aug 12 '15 at 04:05
  • I have not checked it on Mono. See the accepted answer to http://stackoverflow.com/questions/3744032/why-are-net-timers-limited-to-15-ms-resolution for a bit about the source of the 15 ms resolution. The linked document is interesting reading. – Jim Mischel Aug 12 '15 at 10:18
  • Thanks for the example, looks easy and effective. Will try it out! – сами J.D. Aug 12 '15 at 12:49
  • Hi, it's working properly, thanks. I have a problem though. When I execute it and some stuff happens I get either a `accessviolationexception` or `NullReferenceException`. However, VS is not telling me on what line it is happenning and I can't figure it out. How can I discover where the problem is if VS only warns me about the exception but doesn't give any information away, unlike other exceptions? I've been stuck here for a long time now. Thanks EDIT: I've tried with try-catch but it ain't working – сами J.D. Aug 12 '15 at 22:50
  • Sorted it out. Turns out you need a reference to the `TimerEventHandler`. I don't understand it very well but in the scope of the class I did this:` private TimerEventHandler timerLooking4WLRef ; ` And then this is the call to `TimerSetEvent`: `timerLooking4WLRef = new TimerEventHandler(MyFunction); timerIdWLSearch = timeSetEvent(30, 15, timerLooking4WLRef, UIntPtr.Zero, TIME_KILL_SYNCHRONOUS | TIME_PERIODIC);` – сами J.D. Aug 13 '15 at 01:09