如何将计时器分辨率从C#设置为1ms?

如何将计时器分辨率从C#设置为1ms?,c#,timer,windows-server-2008-r2,C#,Timer,Windows Server 2008 R2,我使用并注意到我的Windows Server 2008 R2标准具有15毫秒的分辨率,而Windows 8具有1毫秒的分辨率计时器 我更愿意在Windows Server 2008 R2上将计时器分辨率设置为1毫秒,因为我正在运行低延迟软件 我发现了这个,但它没有解释如何从C#程序更改计时器分辨率。我该怎么做?您可以尝试以下方法: public static class WinApi { /// <summary>TimeBeginPeriod(). See the Win

我使用并注意到我的Windows Server 2008 R2标准具有15毫秒的分辨率,而Windows 8具有1毫秒的分辨率计时器

我更愿意在Windows Server 2008 R2上将计时器分辨率设置为1毫秒,因为我正在运行低延迟软件

我发现了这个,但它没有解释如何从C#程序更改计时器分辨率。我该怎么做?

您可以尝试以下方法:

public static class WinApi
{
    /// <summary>TimeBeginPeriod(). See the Windows API documentation for details.</summary>

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
    [DllImport("winmm.dll", EntryPoint="timeBeginPeriod", SetLastError=true)]

    public static extern uint TimeBeginPeriod(uint uMilliseconds);

    /// <summary>TimeEndPeriod(). See the Windows API documentation for details.</summary>

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
    [DllImport("winmm.dll", EntryPoint="timeEndPeriod", SetLastError=true)]

    public static extern uint TimeEndPeriod(uint uMilliseconds);
}
回到过去:

WinApi.TimeEndPeriod(1);

实现这一点的更好代码是:

using System;
using System.Runtime.InteropServices;
using System.Threading;

internal sealed class TimePeriod : IDisposable
{
    private const string WINMM = "winmm.dll";

    private static TIMECAPS timeCapabilities;

    private static int inTimePeriod;

    private readonly int period;

    private int disposed;

    [DllImport(WINMM, ExactSpelling = true)]
    private static extern int timeGetDevCaps(ref TIMECAPS ptc, int cbtc);

    [DllImport(WINMM, ExactSpelling = true)]
    private static extern int timeBeginPeriod(int uPeriod);

    [DllImport(WINMM, ExactSpelling = true)]
    private static extern int timeEndPeriod(int uPeriod);

    static TimePeriod()
    {
        int result = timeGetDevCaps(ref timeCapabilities, Marshal.SizeOf(typeof(TIMECAPS)));
        if (result != 0)
        {
            throw new InvalidOperationException("The request to get time capabilities was not completed because an unexpected error with code " + result + " occured.");
        }
    }

    internal TimePeriod(int period)
    {
        if (Interlocked.Increment(ref inTimePeriod) != 1)
        {
            Interlocked.Decrement(ref inTimePeriod);
            throw new NotSupportedException("The process is already within a time period. Nested time periods are not supported.");
        }

        if (period < timeCapabilities.wPeriodMin || period > timeCapabilities.wPeriodMax)
        {
            throw new ArgumentOutOfRangeException("period", "The request to begin a time period was not completed because the resolution specified is out of range.");
        }

        int result = timeBeginPeriod(period);
        if (result != 0)
        {
            throw new InvalidOperationException("The request to begin a time period was not completed because an unexpected error with code " + result + " occured.");
        }

        this.period = period;
    }

    internal static int MinimumPeriod
    {
        get
        {
            return timeCapabilities.wPeriodMin;
        }
    }

    internal static int MaximumPeriod
    {
        get
        {
            return timeCapabilities.wPeriodMax;
        }
    }

    internal int Period
    {
        get
        {
            if (this.disposed > 0)
            {
                throw new ObjectDisposedException("The time period instance has been disposed.");
            }

            return this.period;
        }
    }

    public void Dispose()
    {
        if (Interlocked.Increment(ref this.disposed) == 1)
        {
            timeEndPeriod(this.period);
            Interlocked.Decrement(ref inTimePeriod);
        }
        else
        {
            Interlocked.Decrement(ref this.disposed);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct TIMECAPS
    {
        internal int wPeriodMin;

        internal int wPeriodMax;
    }
}

我认为计时器分辨率在某些架构上是有限的(即,您不能将其设置得更低)。是一篇关于如何为Windows实现自己的高分辨率计时器的文章(带有代码示例)。@NominSim您是否阅读了问题中提到的“获取和设置计时器分辨率”文章?是的。如果您阅读了我链接到的文章,它将解释如何根据体系结构限制分辨率。你可以得到更好的解决方案,但你也必须做出妥协。(你不能只设置一个任意的分辨率而不损失一些准确性)。这篇博客文章讨论了使用
timeBeginPeriod()和
timeEndPeriod()更改计时器的一些优缺点
,还提到了Windows 8对计时器分辨率的更改。我是否应该在每次系统重新启动时调用此函数?或者我应该叫它一次?只要你启动系统。它不是持久性的-但它是全局性的(即,它将影响所有进程)!我使用过这种方法-它会影响睡眠,但会影响操作系统计时器线程。计时器保持15毫秒的分辨率-我的问题中有更多细节:准确地说,TimeBeginPeriod的效果会一直持续到调用TimeEndPeriod或进程结束。因此,您通常在进程初始化时调用它。如果您暂时不需要提高计时器频率,那么理想情况下,您应该调用TimeEndPeriod以避免浪费电源,然后在需要再次提高计时器频率时调用TimeBeginPeriod。解释为什么这样做更好会很有用。大多数使用TimeBeginPeriod()的代码都会涉及定期调用的代码。使用“using”的周围代码将推断出其他情况。我不会这样做的。
using System;
using System.Runtime.InteropServices;
using System.Threading;

internal sealed class TimePeriod : IDisposable
{
    private const string WINMM = "winmm.dll";

    private static TIMECAPS timeCapabilities;

    private static int inTimePeriod;

    private readonly int period;

    private int disposed;

    [DllImport(WINMM, ExactSpelling = true)]
    private static extern int timeGetDevCaps(ref TIMECAPS ptc, int cbtc);

    [DllImport(WINMM, ExactSpelling = true)]
    private static extern int timeBeginPeriod(int uPeriod);

    [DllImport(WINMM, ExactSpelling = true)]
    private static extern int timeEndPeriod(int uPeriod);

    static TimePeriod()
    {
        int result = timeGetDevCaps(ref timeCapabilities, Marshal.SizeOf(typeof(TIMECAPS)));
        if (result != 0)
        {
            throw new InvalidOperationException("The request to get time capabilities was not completed because an unexpected error with code " + result + " occured.");
        }
    }

    internal TimePeriod(int period)
    {
        if (Interlocked.Increment(ref inTimePeriod) != 1)
        {
            Interlocked.Decrement(ref inTimePeriod);
            throw new NotSupportedException("The process is already within a time period. Nested time periods are not supported.");
        }

        if (period < timeCapabilities.wPeriodMin || period > timeCapabilities.wPeriodMax)
        {
            throw new ArgumentOutOfRangeException("period", "The request to begin a time period was not completed because the resolution specified is out of range.");
        }

        int result = timeBeginPeriod(period);
        if (result != 0)
        {
            throw new InvalidOperationException("The request to begin a time period was not completed because an unexpected error with code " + result + " occured.");
        }

        this.period = period;
    }

    internal static int MinimumPeriod
    {
        get
        {
            return timeCapabilities.wPeriodMin;
        }
    }

    internal static int MaximumPeriod
    {
        get
        {
            return timeCapabilities.wPeriodMax;
        }
    }

    internal int Period
    {
        get
        {
            if (this.disposed > 0)
            {
                throw new ObjectDisposedException("The time period instance has been disposed.");
            }

            return this.period;
        }
    }

    public void Dispose()
    {
        if (Interlocked.Increment(ref this.disposed) == 1)
        {
            timeEndPeriod(this.period);
            Interlocked.Decrement(ref inTimePeriod);
        }
        else
        {
            Interlocked.Decrement(ref this.disposed);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct TIMECAPS
    {
        internal int wPeriodMin;

        internal int wPeriodMax;
    }
}
using (new TimePeriod(1))
{
    ////...
}