Mono High Resolution timer (on Linux)(单声道高分辨率计时器(在 Linux 上))
问题描述
我正在将一个以 50 毫秒(用于串行通信)轮询的 Windows C# 应用程序移植到 Linux(使用 Mono).我们目前正在使用 ZylTimer(由 ZylSoft 提供)在每个时间间隔生成tick"事件,但是由于这个库将 pInvoke 调用包装到 windows 多媒体库,我们当然不能使用它.
I am porting a windows C# application that polls at 50ms (for serial comms) to Linux (using Mono). We are currently using the ZylTimer (by ZylSoft) to generate "tick" events at each interval , however as this library wraps pInvoke calls to the windows multimedia library, we of course cannot use this.
   //i.e. 
        timZylComms.Tick += new ZylTimer.TickEventHandler(timZylComms_Tick);
        timTimeout.Tick += new ZylTimer.TickEventHandler(timTimeout_Tick);
所以,这让我想问是否存在我可以在 Mono 下使用的替代方案?最好的方法是使用 Tick 事件扩展秒表"类(以高分辨率计算)吗?
So, this leads me to ask if either there exists an alternative I can use under Mono? Would the best approach be to extend the "Stopwatch" class (which counts at a high resolution) with a Tick event?
或者是否有任何我可以包装的 linux 库来重现此功能?还是有其他方法可以实现这一目标?
Or are there any linux libraries I can wrap to reproduce this functionality? Or is there some other way of achieving this?
感谢您对此的任何想法.
Appreciate any thoughts on this.
这样做会有什么问题吗:
Would there be any problems with going with this:
internal class LinuxHiResTimer{
    internal event EventHandler Tick;
    private System.Diagnostics.Stopwatch watch;
    internal int Interval{ get; set;}
    private bool enabled;
    internal bool Enabled {
        get{ return enabled; } 
        set {
            if (value) {
                watch.Start ();
                Task.Run (tickGenerator); 
                enabled = value;
            } else {
                enabled = value;
            }
        }
    }
    private async Task tickGenerator(){
        while (enabled){
            if (watch.ElapsedMilliseconds > Interval) {
                watch.Reset ();
                if (Tick != null)
                    Tick (this, new EventArgs ());
            } else {
                float fWaitPeriod = (float)(0.8 * (Interval - watch.ElapsedMilliseconds));
                if (fWaitPeriod>20)
                    await Task.Delay(TimeSpan.FromMilliseconds(fWaitPeriod));
            }
        }
        watch.Stop ();
    }
    internal LinuxHiResTimer(){
        watch = new Stopwatch ();
    }
    ~LinuxHiResTimer(){
        watch.Stop ();
    }
}
推荐答案
这就是我现在所拥有的.
This is what I have now.
它完成了这项工作(通过在 25 毫秒生成滴答声进行测试).
It does the job (tested with generating ticks at 25ms).
它通过使用 nanosleep() (通过 Mono.Unix.Native 包装器)工作,我想与其他人分享这个,以防他们希望实现类似的东西.
It works by using nanosleep() (through the Mono.Unix.Native wrapper), and I would like to share this with others in case they are looking to implement something similar.
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();
}
                        这篇关于单声道高分辨率计时器(在 Linux 上)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:单声道高分辨率计时器(在 Linux 上)
				
        
 
            
        - C#MongoDB使用Builders查找派生对象 2022-09-04
 - Web Api 中的 Swagger .netcore 3.1,使用 swagger UI 设置日期时间格式 2022-01-01
 - 如何用自己压缩一个 IEnumerable 2022-01-01
 - 在哪里可以找到使用中的C#/XML文档注释的好例子? 2022-01-01
 - 带有服务/守护程序应用程序的 Microsoft Graph CSharp SDK 和 OneDrive for Business - 配额方面返回 null 2022-01-01
 - WebMatrix WebSecurity PasswordSalt 2022-01-01
 - C# 中多线程网络服务器的模式 2022-01-01
 - 输入按键事件处理程序 2022-01-01
 - 良好实践:如何重用 .csproj 和 .sln 文件来为 CI 创建 2022-01-01
 - MoreLinq maxBy vs LINQ max + where 2022-01-01
 
						
						
						
						
						
				
				
				
				