[英]Mono High Resolution timer (on Linux)
I am porting a windows C# application that polls at 50ms (for serial comms) to Linux (using Mono). 我正在移植一个Windows C#应用程序,它以50ms(对于串行通信)轮询到Linux(使用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.
我们目前正在使用ZylTimer(由ZylSoft)在每个时间间隔生成“tick”事件,但是当这个库将pInvoke调用包装到windows多媒体库时,我们当然不能使用它。
//i.e.
timZylComms.Tick += new ZylTimer.TickEventHandler(timZylComms_Tick);
timTimeout.Tick += new ZylTimer.TickEventHandler(timTimeout_Tick);
So, this leads me to ask if either there exists an alternative I can use under Mono? 所以,这让我想问是否存在我可以在Mono下使用的替代方案? Would the best approach be to extend the "Stopwatch" class (which counts at a high resolution) with a Tick event?
最好的方法是使用Tick事件扩展“秒表”类(以高分辨率计算)吗?
Or are there any linux libraries I can wrap to reproduce this functionality? 或者是否有任何我可以包装的linux库来重现这个功能? Or is there some other way of achieving this?
或者还有其他方法可以实现这一目标吗?
Appreciate any thoughts on this. 感谢对此的任何想法。
EDIT: 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. 这就是我现在拥有的。
It does the job (tested with generating ticks at 25ms). 它完成了这项工作(在25ms时生成滴答测试)。
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. 它通过使用nanosleep()(通过Mono.Unix.Native包装器)工作,我想与其他人分享,以防他们想要实现类似的东西。
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;
}
}
Usage: 用法:
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();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.