2013-02-25 9 views
7

Użyłem i zauważyłem, że mój Windows Server 2008 R2 Standard ma rozdzielczość 15 ms, podczas gdy Windows 8 ma czasomierz o rozdzielczości 1 ms.jak ustawić rozdzielczość zegara z C# na 1 ms?

Wolałbym ustawić rozdzielczość timera na 1 ms w systemie Windows Server 2008 R2, ponieważ używam na nim oprogramowania o małym opóźnieniu.

Znalazłem ten msdn article, ale nie wyjaśnia, jak zmienić rozdzielczość Timera z programu C#. Jak mogę to zrobić?

+0

wierzę rozdzielczości zegara jest ograniczony w określonych architekturach (tj nie możesz po prostu ustawić go niżej). [Tutaj] (http://msdn.microsoft.com/en-us/magazine/cc163996.aspx) jest artykułem o tym, jak zaimplementować swój własny zegar o wysokiej rozdzielczości dla Windows (z przykładem kodu). – NominSim

+0

@NominSim Czy przeczytałeś artykuł "Otrzymywanie i ustawianie rozdzielczości czasomierza" w pytaniu? – javapowered

+0

Tak. Jeśli przeczytasz artykuł, do którego się przyłączyłem, wyjaśniam, w jaki sposób rozdzielczość jest ograniczona zgodnie z architekturą. Możesz uzyskać lepszą rozdzielczość, ale są też kompromisy, które musisz wykonać. (Nie możesz po prostu ustawić arbitralnej rozdzielczości bez utraty dokładności). – NominSim

Odpowiedz

11

Można spróbować to:

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); 
} 

i używać go tak:

WinApi.TimeBeginPeriod(1); 

I wrócić do tego, jak to było:

WinApi.TimeEndPeriod(1); 
+1

czy powinienem wywoływać tę funkcję przy każdym ponownym uruchomieniu systemu? czy powinienem to nazwać tylko raz? – javapowered

+2

Zawsze, gdy uruchamiasz system. Nie jest trwały - ale * jest * globalny (to znaczy wpływa na wszystkie procesy)! –

+0

Użyłem tej metody - dotyczy Masztów i zegara OS, jednak Threading.Timer zachowuje swoją rozdzielczość 15 ms - więcej szczegółów na moje pytanie tutaj: http://stackoverflow.com/questions/23215970/system-threading-timer- vs-system-wątek-wątek-sen-rozdzielczość-net-timer – Jan

5

lepszy kod do wdrożenia tego będzie:

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; 
    } 
} 

używać go przez:

using (new TimePeriod(1)) 
{ 
    ////... 
} 
Powiązane problemy