2011-10-12 26 views
1

我正在寻找Mono上的高分辨率刻度计数器,最好是与Win32/.NET上的QueryPerformanceCounter大致相同的分辨率。单声道跨平台高分辨率刻度计?

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

我需要约< 1ms分辨率。

回答

2

您应该为此使用System.Diagnostics.Stopwatch。

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(); 
} 
0

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

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

  1. 它适用于所有平台(所以没有using Mono.Unix.Native;),是高精度的地方StopWatch.IsHighPrecision == true

  2. Elapsed事件是保证非重叠(这可能是知道重要,因为事件处理中的状态变化可能离开对多线程访问未受保护的)

这里是如何使用它:

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 

这里是一个benchmar K(和活的示例):
https://gist.github.com/DraTeots/5f454968ae84122b526651ad2d6ef2a3

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

还值得一提的是:

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

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

  3. Stopwatch ticks are not TimeSpan ticks.在那Windows 10机器 HighResolutionTimer.TickLength为0.23 [ns]。