8个回答
展开全部
这个问题涉及到Windows定时器精度,0.5ms的定时器,只能通过死循环,长期占用一个CPU核心来完成。
Forms.Timer,Threading.Time,System.Timers.Timer,System.Envisonment.TickCount,Kernel32.GetTickCount等等,都只能获取到15ms整数倍的定时器,比如:Thread.Sleep(1)和Thread.Sleep(15)效果是一样的,你可以试试。
我这有个基于死循环长期占用一个CPU核心的定时器,大约能获得最小2微妙的定时器:
/// <summary>
/// 基于系统性能计数器的定时器,计数单位是1微秒=1/1000毫秒
/// 注意:该定时器会独占一个CPU核心,尝试定时器与主程序运行在同一核心将导致程序失去响应
/// </summary>
public class PerformanceTimer
{
/// <summary>
/// 获取当前系统性能计数
/// </summary>
/// <param name="lpPerformanceCount"></param>
/// <returns></returns>
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
/// <summary>
/// 获取当前系统性能频率
/// </summary>
/// <param name="lpFrequency"></param>
/// <returns></returns>
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
/// <summary>
/// 指定某一特定线程运行在指定的CPU核心
/// </summary>
/// <param name="hThread"></param>
/// <param name="dwThreadAffinityMask"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
static extern UIntPtr SetThreadAffinityMask(IntPtr hThread, UIntPtr dwThreadAffinityMask);
/// <summary>
/// 获取当前线程的Handler
/// </summary>
/// <returns></returns>
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThread();
/// <summary>
/// 是否销毁定时器
/// </summary>
private bool _Dispose = false;
/// <summary>
/// 是否正在运行定时器
/// </summary>
private bool _BRunTimer = false;
/// <summary>
/// 首次启动延时(微秒)
/// </summary>
private uint _Delay = 0;
/// <summary>
/// 定时器周期(微秒)
/// </summary>
private long _Period = 10;
/// <summary>
/// 定时器运行时独占的CPU核心索引序号
/// </summary>
private byte _CpuIndex = 0;
/// <summary>
/// 系统性能计数频率(每秒)
/// </summary>
private long _Freq = 0;
/// <summary>
/// 系统性能计数频率(每微秒)
/// </summary>
private long _Freqmms = 0;
/// <summary>
/// 回调函数定义
/// </summary>
private OnTickHandle Tick;
/// <summary>
/// 根据CPU的索引序号获取CPU的标识序号
/// </summary>
/// <param name="idx"></param>
/// <returns></returns>
private ulong GetCpuID(int idx)
{
ulong cpuid = 0;
if (idx < 0 || idx >= System.Environment.ProcessorCount)
{
idx = 0;
}
cpuid |= 1UL << idx;
return cpuid;
}
/// <summary>
/// 定时器构造函数
/// </summary>
/// <param name="delay">首次启动定时器延时时间(微秒)</param>
/// <param name="period">定时器触发的周期(微秒)</param>
/// <param name="cpuIndex">指定定时器线程独占的CPU核心索引,必须>0,不允许为定时器分配0#CPU</param>
/// <param name="tick">定时器触发时的回调函数</param>
public PerformanceTimer(uint delay, uint period, byte cpuIndex, OnTickHandle tick)
{
Tick = tick;
_Delay = delay;
_Period = period;
_CpuIndex = cpuIndex;
long freq = 0;
QueryPerformanceFrequency(out freq);
if (freq > 0)
{
_Freq = freq;
_Freqmms = freq / 1000000;//每微秒性能计数器跳跃次数
}
else
{
throw new Exception("初始化定时器失败");
}
if (_CpuIndex == 0)
{
throw new Exception("定时器不允许被分配到0#CPU");
}
if (_CpuIndex >= System.Environment.ProcessorCount)
{
throw new Exception("为定时器分配了超出索引的CPU");
}
}
private System.Threading.Thread _threadRumTimer;
/// <summary>
/// 开启定时器
/// </summary>
public void Open()
{
if (Tick != null)
{
_threadRumTimer = new System.Threading.Thread(new System.Threading.ThreadStart(RunTimer));
_threadRumTimer.Start();
}
}
/// <summary>
/// 运行定时器
/// </summary>
private void RunTimer()
{
UIntPtr up = UIntPtr.Zero;
if (_CpuIndex != 0)
up = SetThreadAffinityMask(GetCurrentThread(), new UIntPtr(GetCpuID(_CpuIndex)));
if (up == UIntPtr.Zero)
{
throw new Exception("为定时器分配CPU核心时失败");
}
long q1, q2;
QueryPerformanceCounter(out q1);
QueryPerformanceCounter(out q2);
if (_Delay > 0)
{
while (q2 < q1 + _Delay * _Freqmms)
{
QueryPerformanceCounter(out q2);
}
}
QueryPerformanceCounter(out q1);
QueryPerformanceCounter(out q2);
while (!_Dispose)
{
_BRunTimer = true;
QueryPerformanceCounter(out q2);
if (q2 > q1 + _Freqmms * _Period)
{
//***********回调***********//
if (!_Dispose)
Tick(this, (q2 - q1) / (_Freqmms * _Period), (q2 - q1) / _Freqmms);
q1 = q2;
//System.Windows.Forms.Application.DoEvents();//会导致线程等待windows消息循环,时间损失15ms以上
}
_BRunTimer = false;
}
}
/// <summary>
/// 销毁当前定时器所占用的资源
/// </summary>
public void Dispose()
{
_Dispose = true;
while (_BRunTimer)
System.Windows.Forms.Application.DoEvents();//在工作未完成之前,允许处理消息队列,防止调用者挂起
if (_threadRumTimer != null)
_threadRumTimer.Abort();
}
/// <summary>
/// 定时器事件的委托定义
/// </summary>
/// <param name="sender">事件的发起者,即定时器对象</param>
/// <param name="JumpPeriod">上次调用和本次调用跳跃的周期数</param>
/// <param name="interval">上次调用和本次调用之间的间隔时间(微秒)</param>
public delegate void OnTickHandle(object sender, long JumpPeriod, long interval);
}
能问出这个0.5ms定时器问题的选手,类怎么用就不再解释了
Forms.Timer,Threading.Time,System.Timers.Timer,System.Envisonment.TickCount,Kernel32.GetTickCount等等,都只能获取到15ms整数倍的定时器,比如:Thread.Sleep(1)和Thread.Sleep(15)效果是一样的,你可以试试。
我这有个基于死循环长期占用一个CPU核心的定时器,大约能获得最小2微妙的定时器:
/// <summary>
/// 基于系统性能计数器的定时器,计数单位是1微秒=1/1000毫秒
/// 注意:该定时器会独占一个CPU核心,尝试定时器与主程序运行在同一核心将导致程序失去响应
/// </summary>
public class PerformanceTimer
{
/// <summary>
/// 获取当前系统性能计数
/// </summary>
/// <param name="lpPerformanceCount"></param>
/// <returns></returns>
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
/// <summary>
/// 获取当前系统性能频率
/// </summary>
/// <param name="lpFrequency"></param>
/// <returns></returns>
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
/// <summary>
/// 指定某一特定线程运行在指定的CPU核心
/// </summary>
/// <param name="hThread"></param>
/// <param name="dwThreadAffinityMask"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
static extern UIntPtr SetThreadAffinityMask(IntPtr hThread, UIntPtr dwThreadAffinityMask);
/// <summary>
/// 获取当前线程的Handler
/// </summary>
/// <returns></returns>
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThread();
/// <summary>
/// 是否销毁定时器
/// </summary>
private bool _Dispose = false;
/// <summary>
/// 是否正在运行定时器
/// </summary>
private bool _BRunTimer = false;
/// <summary>
/// 首次启动延时(微秒)
/// </summary>
private uint _Delay = 0;
/// <summary>
/// 定时器周期(微秒)
/// </summary>
private long _Period = 10;
/// <summary>
/// 定时器运行时独占的CPU核心索引序号
/// </summary>
private byte _CpuIndex = 0;
/// <summary>
/// 系统性能计数频率(每秒)
/// </summary>
private long _Freq = 0;
/// <summary>
/// 系统性能计数频率(每微秒)
/// </summary>
private long _Freqmms = 0;
/// <summary>
/// 回调函数定义
/// </summary>
private OnTickHandle Tick;
/// <summary>
/// 根据CPU的索引序号获取CPU的标识序号
/// </summary>
/// <param name="idx"></param>
/// <returns></returns>
private ulong GetCpuID(int idx)
{
ulong cpuid = 0;
if (idx < 0 || idx >= System.Environment.ProcessorCount)
{
idx = 0;
}
cpuid |= 1UL << idx;
return cpuid;
}
/// <summary>
/// 定时器构造函数
/// </summary>
/// <param name="delay">首次启动定时器延时时间(微秒)</param>
/// <param name="period">定时器触发的周期(微秒)</param>
/// <param name="cpuIndex">指定定时器线程独占的CPU核心索引,必须>0,不允许为定时器分配0#CPU</param>
/// <param name="tick">定时器触发时的回调函数</param>
public PerformanceTimer(uint delay, uint period, byte cpuIndex, OnTickHandle tick)
{
Tick = tick;
_Delay = delay;
_Period = period;
_CpuIndex = cpuIndex;
long freq = 0;
QueryPerformanceFrequency(out freq);
if (freq > 0)
{
_Freq = freq;
_Freqmms = freq / 1000000;//每微秒性能计数器跳跃次数
}
else
{
throw new Exception("初始化定时器失败");
}
if (_CpuIndex == 0)
{
throw new Exception("定时器不允许被分配到0#CPU");
}
if (_CpuIndex >= System.Environment.ProcessorCount)
{
throw new Exception("为定时器分配了超出索引的CPU");
}
}
private System.Threading.Thread _threadRumTimer;
/// <summary>
/// 开启定时器
/// </summary>
public void Open()
{
if (Tick != null)
{
_threadRumTimer = new System.Threading.Thread(new System.Threading.ThreadStart(RunTimer));
_threadRumTimer.Start();
}
}
/// <summary>
/// 运行定时器
/// </summary>
private void RunTimer()
{
UIntPtr up = UIntPtr.Zero;
if (_CpuIndex != 0)
up = SetThreadAffinityMask(GetCurrentThread(), new UIntPtr(GetCpuID(_CpuIndex)));
if (up == UIntPtr.Zero)
{
throw new Exception("为定时器分配CPU核心时失败");
}
long q1, q2;
QueryPerformanceCounter(out q1);
QueryPerformanceCounter(out q2);
if (_Delay > 0)
{
while (q2 < q1 + _Delay * _Freqmms)
{
QueryPerformanceCounter(out q2);
}
}
QueryPerformanceCounter(out q1);
QueryPerformanceCounter(out q2);
while (!_Dispose)
{
_BRunTimer = true;
QueryPerformanceCounter(out q2);
if (q2 > q1 + _Freqmms * _Period)
{
//***********回调***********//
if (!_Dispose)
Tick(this, (q2 - q1) / (_Freqmms * _Period), (q2 - q1) / _Freqmms);
q1 = q2;
//System.Windows.Forms.Application.DoEvents();//会导致线程等待windows消息循环,时间损失15ms以上
}
_BRunTimer = false;
}
}
/// <summary>
/// 销毁当前定时器所占用的资源
/// </summary>
public void Dispose()
{
_Dispose = true;
while (_BRunTimer)
System.Windows.Forms.Application.DoEvents();//在工作未完成之前,允许处理消息队列,防止调用者挂起
if (_threadRumTimer != null)
_threadRumTimer.Abort();
}
/// <summary>
/// 定时器事件的委托定义
/// </summary>
/// <param name="sender">事件的发起者,即定时器对象</param>
/// <param name="JumpPeriod">上次调用和本次调用跳跃的周期数</param>
/// <param name="interval">上次调用和本次调用之间的间隔时间(微秒)</param>
public delegate void OnTickHandle(object sender, long JumpPeriod, long interval);
}
能问出这个0.5ms定时器问题的选手,类怎么用就不再解释了
展开全部
Thread.Sleep(Convert.ToInt32(1000 / 2)); // 1000毫秒等1秒除以2就是0.5秒
追问
0.5毫秒......
追答
试试用Convert.ToInt32强制转换0.5看行不行。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
采集卡的话,硬件应该是0.5毫秒才发送一次数据吧,直接开启一个线程,while(true)不断采集就行了,再说即使限制0.5毫秒,你采集时也要花费时间的,这个时间是否可以在0.5ms内完成呢
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
循环的话就是每循环一次进程休眠五毫秒Thread.Sleep(5);
更多追问追答
追问
0.5毫秒~~不是5毫秒~
追答
貌似Thread.Sleep();不能用小数吧!只能用int整数
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
开一个线程thread执行委托方法进行数据采集,在方法里利用循环采集数据,每采集完一次让线程sleep0.5ms就可以了。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询