问题描述
我正在将一个以 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 上)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!