c#怎么实现 计时器 稳定且精准?

MichaelGLX 2020-07-06 10:16:25
c# 实现根据时间列表 依次精准 稳定 执行事件? 精度1ms ?
我用Stopwatch时钟 , 有时候会误差到 20ms。

List<int> timeList = new List<int>();
Stopwatch watch = new Stopwatch();
watch.Start();

for (int i = 0; i < timeList.Count; i++)
{
while (watch.ElapsedMilliseconds < timeList[i])
{
}
//事件 --不考虑事件未执行完,时间就超过下次时钟。
}

还有其他线程影响。。
...全文
3711 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
良朋 2020-07-16
  • 打赏
  • 举报
回复
tickes 毫微秒...........
  • 打赏
  • 举报
回复
用图形桌面系统搞1ms精度的控制?

要控制1ms,你应该放弃任何操作系统底层,自己写一个操作系统然后烧到设备上。
threenewbee 2020-07-16
  • 打赏
  • 举报
回复
1ms只有死循环并且要当前进程处于很高的优先级。但是也不能保证,因为windows也不是rtos
github_36000833 2020-07-16
  • 打赏
  • 举报
回复
引用 16 楼 MichaelGLX 的回复:
timeSetEvent api 如何? 有试过吗?
Windows是抢占式多任务操作系统。也就是说,操作系统完全决定进程调度方案,操作系统可以剥夺进程的时间片,提供给其它进程。 你的进程,用timeSetEvent也好,用QueryPerformanceCounter也好,不能从根本上排除被操作系统挂起的可能性。 如果在某个15毫秒内,你的进程一点CPU的机会都没有,又如果去保证1毫秒的操作精度?
MichaelGLX 2020-07-16
  • 打赏
  • 举报
回复
引用 5 楼 github_36000833 的回复:
如果实时操作是硬要求(比如输变电控制),那么你不能用C#,甚至Windows系统也不合适。 因为C#不支持实时操作,Windows系统也不是实时操作系统
timeSetEvent api 如何? 有试过吗?
MichaelGLX 2020-07-16
  • 打赏
  • 举报
回复
引用 13 楼 wanghui0380 的回复:
这有一个讨论了N多年的问题,回答是“不可能” https://bbs.csdn.net/topics/330087416 因为windows不是为这种要求设计的系统。跑在windows系统的程序也不需要这种需求(多任务) 如果你一定要如此,只能如上面的帖子尽量选择一个相对“精确”的方案 如果说非要非要,我们只能建议你使用“DDK”编写底层驱动,尝试直接下时钟中断拦截试试
timeSetEvent api 如何? 有试过吗?
lvbinlt 2020-07-08
  • 打赏
  • 举报
回复
毫秒级?那你不能用.net 运行时不是实时的。有C++吧。如果你要求特别特别精确,推荐你做单片机。
wanghui0380 2020-07-07
  • 打赏
  • 举报
回复
这有一个讨论了N多年的问题,回答是“不可能” https://bbs.csdn.net/topics/330087416 因为windows不是为这种要求设计的系统。跑在windows系统的程序也不需要这种需求(多任务) 如果你一定要如此,只能如上面的帖子尽量选择一个相对“精确”的方案 如果说非要非要,我们只能建议你使用“DDK”编写底层驱动,尝试直接下时钟中断拦截试试
八爻老骥 2020-07-07
  • 打赏
  • 举报
回复
引用 11 楼 MichaelGLX 的回复:
[quote=引用 10 楼 xuzuning 的回复:]
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;

namespace HighTimer
{
public class TimerEventArgs : EventArgs
{
private long clockFrequency;
public long ClockFrequency
{
get { return clockFrequency; }
}
private long previousTickCount;
public long PreviousTickOunt
{
get { return previousTickCount; }
}

private long currentTickCount;
public long CurrentTickCount
{
get { return currentTickCount; }
}

public TimerEventArgs(long clockFreq, long prevTick, long currTick)
{
this.clockFrequency = clockFreq;
this.previousTickCount = prevTick;
this.currentTickCount = currTick;
}
}
/// <summary>
/// 高精度定时器事件委托
/// </summary>
public delegate void HighTimerEventHandler(object sender,TimerEventArgs e);

public class HighAccurateTimer
{
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);


public event HighTimerEventHandler Elapsed;

Thread thread;
private object threadLock = new object();

private long clockFrequency = 0;
private long intevalTicks = 0;
private long nextTriggerTime = 0;

private int intervalMs;
/// <summary>
/// 定时器间隔
/// </summary>
public int Interval
{
get
{
return intervalMs;
}
set
{
intervalMs = value;

}
}

private bool enable;
/// <summary>
/// 启动定时器标志
/// </summary>
public bool Enabled
{
get
{
return enable;
}
set
{
enable = value;
if (value == true)
{
intevalTicks = (long)(((double)intervalMs / (double)1000) * (double)clockFrequency);
long currTick = 0;
GetTick(out currTick);
nextTriggerTime = currTick + intevalTicks;
}
}
}
/// <summary>
/// 构造函数
/// </summary>
public HighAccurateTimer()
{
if (QueryPerformanceFrequency(out clockFrequency) == false)
{
return;
}
this.intervalMs = 1000;
this.enable = false;

thread = new Thread(new ThreadStart(ThreadProc));
thread.Name = "HighAccuracyTimer";
thread.Priority = ThreadPriority.Highest;
thread.Start();

}

/// <summary>
/// 进程主程序
/// </summary>
private void ThreadProc()
{
long currTime;
GetTick(out currTime);
nextTriggerTime = currTime + intevalTicks;
while (true)
{
while (currTime < nextTriggerTime)
{
GetTick(out currTime); //决定时钟的精度
}
nextTriggerTime = currTime + intevalTicks;

if (Elapsed != null && enable == true)
{
Elapsed(this, new TimerEventArgs(clockFrequency, currTime - intevalTicks, currTime));
}
}
}
/// <summary>
/// 获得当前时钟计数
/// </summary>
/// <param name="currentTickCount">时钟计数</param>
/// <returns>获得是否成功</returns>
public bool GetTick(out long currentTickCount)
{
if (QueryPerformanceCounter(out currentTickCount) == false)
{
return false;
}
else
{
return true;
}
}
/// <summary>
/// 注销定时器
/// </summary>
public void Destroy()
{
enable = false;
thread.Abort();
}
}

}

这个方法做的计时器我也用过,不太稳定。[/quote]
不要在事件里启动新线程,新建thread是要时间的,而是用基于线程池的Task,这样精度可能会高点。
MichaelGLX 2020-07-07
  • 打赏
  • 举报
回复
引用 10 楼 xuzuning 的回复:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;

namespace HighTimer
{
    public class TimerEventArgs : EventArgs
    {
        private long clockFrequency;
        public long ClockFrequency
        {
            get { return clockFrequency; }
        }
        private long previousTickCount;
        public long PreviousTickOunt
        {
            get { return previousTickCount; }
        }

        private long currentTickCount;
        public long CurrentTickCount
        {
            get { return currentTickCount; }
        }

        public TimerEventArgs(long clockFreq, long prevTick, long currTick)
        {
            this.clockFrequency = clockFreq;
            this.previousTickCount = prevTick;
            this.currentTickCount = currTick;
        }
    }
    /// <summary>
    /// 高精度定时器事件委托
    /// </summary>
    public delegate void HighTimerEventHandler(object sender,TimerEventArgs e);

    public class HighAccurateTimer
    {
        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(out  long lpFrequency);


        public event HighTimerEventHandler Elapsed;

        Thread thread;
        private object threadLock = new object();

        private long clockFrequency = 0;
        private long intevalTicks = 0;
        private long nextTriggerTime = 0;

        private int intervalMs;
        /// <summary>
        /// 定时器间隔
        /// </summary>
        public int Interval
        {
            get 
            {
                return intervalMs; 
            }
            set
            {
                intervalMs = value;
                
            }
        }

        private bool enable;
        /// <summary>
        /// 启动定时器标志
        /// </summary>
        public bool Enabled
        {
            get 
            { 
                return enable; 
            }
            set 
            {
                enable = value;
                if (value == true)
                {
                    intevalTicks = (long)(((double)intervalMs / (double)1000) * (double)clockFrequency);
                    long currTick = 0;
                    GetTick(out currTick);
                    nextTriggerTime = currTick + intevalTicks;
                }
            }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        public HighAccurateTimer()
        {
            if (QueryPerformanceFrequency(out clockFrequency) == false)
            {
                return;
            }
            this.intervalMs = 1000;
            this.enable = false;

            thread = new Thread(new ThreadStart(ThreadProc));
            thread.Name = "HighAccuracyTimer";
            thread.Priority = ThreadPriority.Highest;
            thread.Start();
          
        }

        /// <summary>
        /// 进程主程序
        /// </summary>
        private void ThreadProc()
        {
            long currTime;
            GetTick(out currTime);
            nextTriggerTime = currTime + intevalTicks;
            while (true)
            {
                while (currTime < nextTriggerTime)
                {
                    GetTick(out currTime); //决定时钟的精度
                }
                nextTriggerTime = currTime + intevalTicks;

                if (Elapsed != null && enable == true)
                {
                    Elapsed(this, new TimerEventArgs(clockFrequency, currTime - intevalTicks, currTime));
                }
            }
        }
        /// <summary>
        /// 获得当前时钟计数
        /// </summary>
        /// <param name="currentTickCount">时钟计数</param>
        /// <returns>获得是否成功</returns>
        public bool GetTick(out long currentTickCount)
        {
            if (QueryPerformanceCounter(out currentTickCount) == false)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        /// <summary>
        /// 注销定时器
        /// </summary>
        public void Destroy()
        {
            enable = false;
            thread.Abort();
        }
    }

}

这个方法做的计时器我也用过,不太稳定。
MichaelGLX 2020-07-06
  • 打赏
  • 举报
回复
引用 2 楼 杀马特丶蛮牛 的回复:

static async void test()
        {
            List<int> timeList = new List<int>() { 2, 4, 6, 8 };
            Console.WriteLine($"当前时间:{DateTime.Now}");
            foreach (var item in timeList)
            {
                Task t = Task.Run(async () =>
                {
                    await Task.Delay(item * 1000);
                    Console.WriteLine(DateTime.Now + $":{item}秒后执行输出:{item}");
                });
                await t;
            }
        }
引用 2 楼 杀马特丶蛮牛 的回复:

static async void test()
        {
            List<int> timeList = new List<int>() { 2, 4, 6, 8 };
            Console.WriteLine($"当前时间:{DateTime.Now}");
            foreach (var item in timeList)
            {
                Task t = Task.Run(async () =>
                {
                    await Task.Delay(item * 1000);
                    Console.WriteLine(DateTime.Now + $":{item}秒后执行输出:{item}");
                });
                await t;
            }
        }
并不是很精准。
杀马特丶蛮牛 2020-07-06
  • 打赏
  • 举报
回复

static async void test()
        {
            List<int> timeList = new List<int>() { 2, 4, 6, 8 };
            Console.WriteLine($"当前时间:{DateTime.Now}");
            foreach (var item in timeList)
            {
                Task t = Task.Run(async () =>
                {
                    await Task.Delay(item * 1000);
                    Console.WriteLine(DateTime.Now + $":{item}秒后执行输出:{item}");
                });
                await t;
            }
        }
  • 打赏
  • 举报
回复
可考虑使用异步
xuzuning 2020-07-06
  • 打赏
  • 举报
回复
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;

namespace HighTimer
{
    public class TimerEventArgs : EventArgs
    {
        private long clockFrequency;
        public long ClockFrequency
        {
            get { return clockFrequency; }
        }
        private long previousTickCount;
        public long PreviousTickOunt
        {
            get { return previousTickCount; }
        }

        private long currentTickCount;
        public long CurrentTickCount
        {
            get { return currentTickCount; }
        }

        public TimerEventArgs(long clockFreq, long prevTick, long currTick)
        {
            this.clockFrequency = clockFreq;
            this.previousTickCount = prevTick;
            this.currentTickCount = currTick;
        }
    }
    /// <summary>
    /// 高精度定时器事件委托
    /// </summary>
    public delegate void HighTimerEventHandler(object sender,TimerEventArgs e);

    public class HighAccurateTimer
    {
        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(out  long lpFrequency);


        public event HighTimerEventHandler Elapsed;

        Thread thread;
        private object threadLock = new object();

        private long clockFrequency = 0;
        private long intevalTicks = 0;
        private long nextTriggerTime = 0;

        private int intervalMs;
        /// <summary>
        /// 定时器间隔
        /// </summary>
        public int Interval
        {
            get 
            {
                return intervalMs; 
            }
            set
            {
                intervalMs = value;
                
            }
        }

        private bool enable;
        /// <summary>
        /// 启动定时器标志
        /// </summary>
        public bool Enabled
        {
            get 
            { 
                return enable; 
            }
            set 
            {
                enable = value;
                if (value == true)
                {
                    intevalTicks = (long)(((double)intervalMs / (double)1000) * (double)clockFrequency);
                    long currTick = 0;
                    GetTick(out currTick);
                    nextTriggerTime = currTick + intevalTicks;
                }
            }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        public HighAccurateTimer()
        {
            if (QueryPerformanceFrequency(out clockFrequency) == false)
            {
                return;
            }
            this.intervalMs = 1000;
            this.enable = false;

            thread = new Thread(new ThreadStart(ThreadProc));
            thread.Name = "HighAccuracyTimer";
            thread.Priority = ThreadPriority.Highest;
            thread.Start();
          
        }

        /// <summary>
        /// 进程主程序
        /// </summary>
        private void ThreadProc()
        {
            long currTime;
            GetTick(out currTime);
            nextTriggerTime = currTime + intevalTicks;
            while (true)
            {
                while (currTime < nextTriggerTime)
                {
                    GetTick(out currTime); //决定时钟的精度
                }
                nextTriggerTime = currTime + intevalTicks;

                if (Elapsed != null && enable == true)
                {
                    Elapsed(this, new TimerEventArgs(clockFrequency, currTime - intevalTicks, currTime));
                }
            }
        }
        /// <summary>
        /// 获得当前时钟计数
        /// </summary>
        /// <param name="currentTickCount">时钟计数</param>
        /// <returns>获得是否成功</returns>
        public bool GetTick(out long currentTickCount)
        {
            if (QueryPerformanceCounter(out currentTickCount) == false)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        /// <summary>
        /// 注销定时器
        /// </summary>
        public void Destroy()
        {
            enable = false;
            thread.Abort();
        }
    }

}

  • 打赏
  • 举报
回复
你换系统吧
eggplane 2020-07-06
  • 打赏
  • 举报
回复
1ms? 不可能,干嘛要这么精确?除非你加硬件设备,外部时钟定时触发,然后你写个设备驱动,在驱动里处理
  • 打赏
  • 举报
回复
试试用异步线程定时器, System.Threading.Timer
github_36000833 2020-07-06
  • 打赏
  • 举报
回复
引用 5 楼 github_36000833 的回复:
...因为C#不支持实时操作...
用词更准确的说,Dotnet CLR不支持实时操作。比如垃圾回收本身就是不确定的,而且会挂起线程,比如Task调度是不确定的等等。
github_36000833 2020-07-06
  • 打赏
  • 举报
回复
如果实时操作是硬要求(比如输变电控制),那么你不能用C#,甚至Windows系统也不合适。 因为C#不支持实时操作,Windows系统也不是实时操作系统
MichaelGLX 2020-07-06
  • 打赏
  • 举报
回复
还有其他方法 吗?

111,093

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧