Mono上的跨平台高分辨率计时器?

时间:2011-10-12 06:17:20

标签: c# .net linux macos mono

我正在寻找Mono上的高分辨率计时器,最好与Win32 / .NET上的QueryPerformanceCounter具有相同的分辨率。

这是否需要在我需要支持的每个平台上作为本机调用(如QueryPerformanceCounter在.NET / Win32上)实现? (Linux,OSX)。

我需要大约1毫秒的分辨率。

3 个答案:

答案 0 :(得分:2)

您应该使用System.Diagnostics.Stopwatch。

答案 1 :(得分:1)

请在此处查看我的回答: https://stackoverflow.com/a/37882723/5073786

using Mono.Unix.Native;
namespace drone.StackOverflow{

  internal class LinuxHiResTimer {
    internal event EventHandler Tick; // Tick event 

    private System.Diagnostics.Stopwatch watch; // High resolution time
    const uint safeDelay = 0; // millisecond (for slightly early wakeup)
    private Timespec pendingNanosleepParams = new Timespec();
    private Timespec threadNanosleepParams = new Timespec();
    object lockObject = new object();
    internal long Interval { 
        get{
            double totalNanoseconds;
            lock (lockObject) {
                totalNanoseconds= (1e9 * pendingNanosleepParams.tv_sec)
                                         + pendingNanosleepParams.tv_nsec; 


            }
            return (int)(totalNanoseconds * 1e-6);//return value in ms
        } 
        set{
            lock (lockObject) {
                pendingNanosleepParams.tv_sec = value / 1000;
                pendingNanosleepParams.tv_nsec = (long)((value % 1000) * 1e6);//set value in ns
            }
        }
    }
    private bool enabled;
    internal bool Enabled {
        get { return enabled; }
        set {
            if (value) {
                watch.Start();
                enabled = value;
                Task.Run(()=>tickGenerator()); // fire up new thread
            }
            else {
                lock (lockObject) {
                    enabled = value;
                }
            }
        }

    }
    private Task tickGenerator() {
        bool bNotPendingStop; 
        lock (lockObject) {
            bNotPendingStop = enabled;
        }
        while (bNotPendingStop) {
            // Check if thread has been told to halt

            lock (lockObject) {
                bNotPendingStop = enabled;
            }
            long curTime = watch.ElapsedMilliseconds;
                if (curTime >= Interval) {
                    watch.Restart ();
                    if (Tick != null)
                        Tick (this, new EventArgs ());
                } else {
                    long iTimeLeft = (Interval - curTime); // How long to delay for 
                    if (iTimeLeft >= safeDelay) { // Task.Delay has resolution 15ms//await Task.Delay(TimeSpan.FromMilliseconds(iTimeLeft - safeDelay));
                        threadNanosleepParams.tv_nsec = (int)((iTimeLeft - safeDelay) * 1e6);
                        threadNanosleepParams.tv_sec = 0;
                        Syscall.nanosleep (ref threadNanosleepParams, ref threadNanosleepParams);
                    }
                }

        }
        watch.Stop();
        return null;
    }
}

用法:

 private myMainFunction(){
  LinuxHiResTimer timReallyFast = new LinuxHiResTimer();
  timReallyFast.Interval=25; // 
  timReallyFast.Tick += new EventHandler(timReallyFast_Tick);
  timReallyFast.Enabled = true;
}
private void timReallyFast_Tick(System.Object sender, System.EventArgs e) {
// Do this quickly i.e. 
 PollSerialPort();
}

答案 2 :(得分:1)

这是我在这里的回答High resolution timer

https://gist.github.com/DraTeots/436019368d32007284f8a12f1ba0f545

  1. 它适用于所有平台(因此没有using Mono.Unix.Native;),并且只要StopWatch.IsHighPrecision == true

  2. 就具有高精度
  3. 它的Elapsed事件保证不重叠(这可能很重要,因为事件处理程序中的状态更改可能不受多线程访问保护)

  4. 以下是如何使用它:

    Console.WriteLine($"IsHighResolution = {HighResolutionTimer.IsHighResolution}");
    Console.WriteLine($"Tick time length = {HighResolutionTimer.TickLength} [ms]");
    
    var timer = new HighResolutionTimer(0.5f);
    
    // UseHighPriorityThread = true, sets the execution thread 
    // to ThreadPriority.Highest.  It doesn't provide any precision gain
    // in most of the cases and may do things worse for other threads. 
    // It is suggested to do some studies before leaving it true
    timer.UseHighPriorityThread = false;
    
    timer.Elapsed += (s, e) => { /*... e.Delay */ }; // The call back
    timer.Start();  
    timer.Stop();    // by default Stop waits for thread.Join()
                     // which, if called not from Elapsed subscribers,
                     // would mean that all Elapsed subscribers
                     // are finished when the Stop function exits 
    timer.Stop(joinThread:false)   // Use if you don't care and don't want to wait
    

    这是一个基准(和实例):
    https://gist.github.com/DraTeots/5f454968ae84122b526651ad2d6ef2a3

    在Windows 10上将计时器设置为0.5毫秒的结果: enter image description here

    值得一提的是:

    1. 我在Ubuntu上的单声道精度相同。

    2. 在玩基准时,我看到的最大和非常罕见的偏差约为0.5毫秒 (这可能意味着什么,它不是实时系统,但仍然值得一提)

    3. Stopwatch ticks are not TimeSpan ticks. 在该Windows 10计算机上 HighResolutionTimer.TickLength为0.23 [ns]。