2013-02-25 13 views
7

Ho usato this tool e ho notato che il mio Windows Server 2008 R2 Standard ha una risoluzione di 15 ms mentre Windows 8 ha un timer di risoluzione di 1 ms.come impostare la risoluzione del timer da C# a 1 ms?

Preferirei impostare la risoluzione del timer su 1 ms su Windows Server 2008 R2 perché su di esso è installato un software a bassa latenza.

Ho trovato questo msdn article, ma non spiega come modificare la risoluzione del timer da un programma C#. Come lo faccio?

+0

Credo la risoluzione del timer è limitato su alcune architetture (cioè non puoi semplicemente abbassarlo). [Here] (http://msdn.microsoft.com/en-us/magazine/cc163996.aspx) è un articolo su come implementare il proprio timer ad alta risoluzione per Windows (con esempio di codice). – NominSim

+0

@NominSim hai letto l'articolo "Ottenere e impostare la risoluzione del timer" nella domanda? – javapowered

+0

Sì. Se leggi l'articolo a cui ti ho collegato, spiega come la risoluzione è limitata in base all'architettura. Puoi ottenere una risoluzione migliore, ma ci sono dei compromessi che devi fare anche tu. (Non puoi semplicemente impostare una risoluzione arbitraria senza il potenziale di perdere un po 'di precisione). – NominSim

risposta

11

Si può provare questo:

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

e usarlo in questo modo:

WinApi.TimeBeginPeriod(1); 

E per tornare a come era:

WinApi.TimeEndPeriod(1); 
+1

dovrei chiamare questa funzione ogni volta che si riavvia il sistema? o dovrei chiamarlo solo una volta? – javapowered

+2

Ogni volta che si avvia il sistema. Non è persistente, ma * è * globale (cioè influenzerà tutti i processi)! –

+0

Ho usato questo metodo - influenza Sleep e timer del sistema operativo, tuttavia Threading.Timer mantiene la risoluzione di 15ms - ulteriori dettagli nella mia domanda qui: http://stackoverflow.com/questions/23215970/system-threading-timer- vs-system-threading-thread-sleep-resolution-net-timer – Jan

5

Meglio codice per implementare questo sarebbe:

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

Utilizzare tramite:

using (new TimePeriod(1)) 
{ 
    ////... 
} 
Problemi correlati