TimeBeginPeriod / TimeEndPeriod 序列
TimeBeginPeriod / TimeEndPeriod Sequence
我有两个 Windows .NET 库 A 和 B。库 A 有 TimeBeginPeriod(1) 和 TimeEndPeriod(1),而库 B 有 TimeBeginPeriod(5) 和 TimeEndPeriod(5)。我最近注意到(在他们 behavor change 之后),当图书馆 B 执行 TimeEndPeriod(5) 时,图书馆 A 失去 TimeBeginPeriod(1).
您可以在同一个应用程序中设置不同的时间段而不影响另一个吗?我的意思是我不介意 (5) 是否会受到 (1) 的影响,但是 end(5) 不会影响 begin(1) 是至关重要的!
LibA TimeBeginPeriod(1)
.... LibB TimeBeginPeriod(5)
.... LibB TimeEndPeriod(5) <- Does this cancel TimeBeginPeriod(1)?
LibA TimeEndPeriod(1)
[更新]
测试代码
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static long freq;
static void Main(string[] args)
{
QueryPerformanceFrequency(out freq);
Console.WriteLine("Begin");
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
TimeBeginPeriod(1);
Console.WriteLine("TimeBeginPeriod(1)");
Thread.Sleep(5000);
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
TimeBeginPeriod(15);
Console.WriteLine("TimeBeginPeriod(15)");
Thread.Sleep(5000);
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine("TimeEndPeriod(15)");
TimeEndPeriod(15);
Thread.Sleep(5000);
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
TimeEndPeriod(1);
Console.WriteLine("TimeEndPeriod(1)");
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine("End");
}
private static string CalcSleep1()
{
QueryPerformanceCounter(out long ticks1);
Thread.Sleep(1);
QueryPerformanceCounter(out long ticks2);
return (new TimeSpan((long)(1000 * 10000 * (ticks2 - ticks1) / (double)freq))).ToString();
}
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
public static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
public static extern uint TimeEndPeriod(uint uMilliseconds);
[DllImport("winmm.dll", ExactSpelling = true)]
private static extern int timeGetDevCaps(ref TIMECAPS ptc, int cbtc);
[StructLayout(LayoutKind.Sequential)]
private struct TIMECAPS
{
internal int wPeriodMin;
internal int wPeriodMax;
}
}
}
输出
Begin
00:00:00.0130730
00:00:00.0154164
TimeBeginPeriod(1)
00:00:00.0019935
00:00:00.0019148
00:00:00.0019145
00:00:00.0019203
00:00:00.0023354
TimeBeginPeriod(15)
00:00:00.0019916
00:00:00.0018920
00:00:00.0019412
00:00:00.0019411
00:00:00.0019336
TimeEndPeriod(15)
00:00:00.0019918
00:00:00.0019300
00:00:00.0019671
00:00:00.0019524
00:00:00.0019399
TimeEndPeriod(1)
00:00:00.0152576
00:00:00.0148129
End
似乎 TimeBeginPeriod(15) / TimeEndPeriod(15) 之间的时间不影响 TimeBeginPeriod(1)。除非这只发生在不同的程序集上(尚未测试)
通过用一个较小的示例编写我的应用程序的逻辑代码,我能够重现并识别出一个严重的 Windows 错误。 动态加载程序集时会发生这种情况。您可以下载解决方案and/or已编译here
更新:它发生在两个 static/dynamic 上。当全局计时器更改时,它具有不同的行为。我的应用程序正在做的是 Windows 不喜欢的以下内容:
.... LibB TimeBeginPeriod(5)
LibA TimeBeginPeriod(1)
.... LibB TimeEndPeriod(5) <- This affects TimeBeginPeriod(1) goes back to 15ms - and it happens when the global timer is already to 1ms? -
LibA TimeEndPeriod(1)
我敢打赌这个问题会影响许多应用程序,因为它们并不真正了解底层库如何处理时间段。
(将Class12 dll复制到控制台应用程序输出)
11 级
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace ClassLibrary1
{
public abstract class ClassAbstract
{
public abstract void StartSample(uint ms);
public abstract void EndSample(uint ms);
public abstract void PrintSample();
}
public class Class11
{
static long freq;
public Class11()
{
QueryPerformanceFrequency(out freq);
}
private static string CalcSleep1()
{
QueryPerformanceCounter(out long ticks1);
Thread.Sleep(1);
QueryPerformanceCounter(out long ticks2);
return (new TimeSpan((long)(1000 * 10000 * (ticks2 - ticks1) / (double)freq))).ToString();
}
public void StartSample(uint ms)
{
TimeBeginPeriod(ms);
Console.WriteLine($"TimeBeginPeriod({ms})");
PrintSample();
}
public void EndSample(uint ms)
{
Console.WriteLine($"TimeEndPeriod({ms})");
TimeEndPeriod(ms);
}
public void PrintSample()
{
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
}
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
public static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
public static extern uint TimeEndPeriod(uint uMilliseconds);
}
}
12 级
using System;
using System.Runtime.InteropServices;
using System.Threading;
using ClassLibrary1;
namespace ClassLibrary2
{
public class Class12 : ClassAbstract
{
static long freq;
public Class12()
{
QueryPerformanceFrequency(out freq);
}
private static string CalcSleep1()
{
QueryPerformanceCounter(out long ticks1);
Thread.Sleep(1);
QueryPerformanceCounter(out long ticks2);
return (new TimeSpan((long)(1000 * 10000 * (ticks2 - ticks1) / (double)freq))).ToString();
}
public override void StartSample(uint ms)
{
TimeBeginPeriod(ms);
Console.WriteLine($"TimeBeginPeriod({ms})");
PrintSample();
}
public override void EndSample(uint ms)
{
Console.WriteLine($"TimeEndPeriod({ms})");
TimeEndPeriod(ms);
}
public override void PrintSample()
{
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
}
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
public static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
public static extern uint TimeEndPeriod(uint uMilliseconds);
}
}
ConsoleApp
using System;
using System.IO;
using System.Reflection;
using ClassLibrary1;
namespace ConsoleApp1
{
class Program
{
static Class11 class11;
static ClassAbstract class12;
static void Main(string[] args)
{
class11 = new Class11();
var assembly = Assembly.LoadFrom(Path.GetFullPath(@"ClassLibrary2.dll"));
ClassAbstract class12 = (ClassAbstract) Activator.CreateInstance(assembly.GetTypes()[0]);
// Behavior changes while System global time period changes
class12.StartSample(5); // Bug here we get 1ms instead of 5ms
class11.StartSample(1);
class12.EndSample(5);
class11.PrintSample(); // Bug Here we get 15 ms period instead of 1ms
class11.EndSample(1);
}
}
}
我有两个 Windows .NET 库 A 和 B。库 A 有 TimeBeginPeriod(1) 和 TimeEndPeriod(1),而库 B 有 TimeBeginPeriod(5) 和 TimeEndPeriod(5)。我最近注意到(在他们 behavor change 之后),当图书馆 B 执行 TimeEndPeriod(5) 时,图书馆 A 失去 TimeBeginPeriod(1).
您可以在同一个应用程序中设置不同的时间段而不影响另一个吗?我的意思是我不介意 (5) 是否会受到 (1) 的影响,但是 end(5) 不会影响 begin(1) 是至关重要的!
LibA TimeBeginPeriod(1)
.... LibB TimeBeginPeriod(5)
.... LibB TimeEndPeriod(5) <- Does this cancel TimeBeginPeriod(1)?
LibA TimeEndPeriod(1)
[更新]
测试代码
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static long freq;
static void Main(string[] args)
{
QueryPerformanceFrequency(out freq);
Console.WriteLine("Begin");
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
TimeBeginPeriod(1);
Console.WriteLine("TimeBeginPeriod(1)");
Thread.Sleep(5000);
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
TimeBeginPeriod(15);
Console.WriteLine("TimeBeginPeriod(15)");
Thread.Sleep(5000);
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine("TimeEndPeriod(15)");
TimeEndPeriod(15);
Thread.Sleep(5000);
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
TimeEndPeriod(1);
Console.WriteLine("TimeEndPeriod(1)");
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine("End");
}
private static string CalcSleep1()
{
QueryPerformanceCounter(out long ticks1);
Thread.Sleep(1);
QueryPerformanceCounter(out long ticks2);
return (new TimeSpan((long)(1000 * 10000 * (ticks2 - ticks1) / (double)freq))).ToString();
}
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
public static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
public static extern uint TimeEndPeriod(uint uMilliseconds);
[DllImport("winmm.dll", ExactSpelling = true)]
private static extern int timeGetDevCaps(ref TIMECAPS ptc, int cbtc);
[StructLayout(LayoutKind.Sequential)]
private struct TIMECAPS
{
internal int wPeriodMin;
internal int wPeriodMax;
}
}
}
输出
Begin
00:00:00.0130730
00:00:00.0154164
TimeBeginPeriod(1)
00:00:00.0019935
00:00:00.0019148
00:00:00.0019145
00:00:00.0019203
00:00:00.0023354
TimeBeginPeriod(15)
00:00:00.0019916
00:00:00.0018920
00:00:00.0019412
00:00:00.0019411
00:00:00.0019336
TimeEndPeriod(15)
00:00:00.0019918
00:00:00.0019300
00:00:00.0019671
00:00:00.0019524
00:00:00.0019399
TimeEndPeriod(1)
00:00:00.0152576
00:00:00.0148129
End
似乎 TimeBeginPeriod(15) / TimeEndPeriod(15) 之间的时间不影响 TimeBeginPeriod(1)。除非这只发生在不同的程序集上(尚未测试)
通过用一个较小的示例编写我的应用程序的逻辑代码,我能够重现并识别出一个严重的 Windows 错误。 动态加载程序集时会发生这种情况。您可以下载解决方案and/or已编译here
更新:它发生在两个 static/dynamic 上。当全局计时器更改时,它具有不同的行为。我的应用程序正在做的是 Windows 不喜欢的以下内容:
.... LibB TimeBeginPeriod(5)
LibA TimeBeginPeriod(1)
.... LibB TimeEndPeriod(5) <- This affects TimeBeginPeriod(1) goes back to 15ms - and it happens when the global timer is already to 1ms? -
LibA TimeEndPeriod(1)
我敢打赌这个问题会影响许多应用程序,因为它们并不真正了解底层库如何处理时间段。
(将Class12 dll复制到控制台应用程序输出)
11 级
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace ClassLibrary1
{
public abstract class ClassAbstract
{
public abstract void StartSample(uint ms);
public abstract void EndSample(uint ms);
public abstract void PrintSample();
}
public class Class11
{
static long freq;
public Class11()
{
QueryPerformanceFrequency(out freq);
}
private static string CalcSleep1()
{
QueryPerformanceCounter(out long ticks1);
Thread.Sleep(1);
QueryPerformanceCounter(out long ticks2);
return (new TimeSpan((long)(1000 * 10000 * (ticks2 - ticks1) / (double)freq))).ToString();
}
public void StartSample(uint ms)
{
TimeBeginPeriod(ms);
Console.WriteLine($"TimeBeginPeriod({ms})");
PrintSample();
}
public void EndSample(uint ms)
{
Console.WriteLine($"TimeEndPeriod({ms})");
TimeEndPeriod(ms);
}
public void PrintSample()
{
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
}
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
public static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
public static extern uint TimeEndPeriod(uint uMilliseconds);
}
}
12 级
using System;
using System.Runtime.InteropServices;
using System.Threading;
using ClassLibrary1;
namespace ClassLibrary2
{
public class Class12 : ClassAbstract
{
static long freq;
public Class12()
{
QueryPerformanceFrequency(out freq);
}
private static string CalcSleep1()
{
QueryPerformanceCounter(out long ticks1);
Thread.Sleep(1);
QueryPerformanceCounter(out long ticks2);
return (new TimeSpan((long)(1000 * 10000 * (ticks2 - ticks1) / (double)freq))).ToString();
}
public override void StartSample(uint ms)
{
TimeBeginPeriod(ms);
Console.WriteLine($"TimeBeginPeriod({ms})");
PrintSample();
}
public override void EndSample(uint ms)
{
Console.WriteLine($"TimeEndPeriod({ms})");
TimeEndPeriod(ms);
}
public override void PrintSample()
{
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
Console.WriteLine(CalcSleep1());
}
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
public static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
public static extern uint TimeEndPeriod(uint uMilliseconds);
}
}
ConsoleApp
using System;
using System.IO;
using System.Reflection;
using ClassLibrary1;
namespace ConsoleApp1
{
class Program
{
static Class11 class11;
static ClassAbstract class12;
static void Main(string[] args)
{
class11 = new Class11();
var assembly = Assembly.LoadFrom(Path.GetFullPath(@"ClassLibrary2.dll"));
ClassAbstract class12 = (ClassAbstract) Activator.CreateInstance(assembly.GetTypes()[0]);
// Behavior changes while System global time period changes
class12.StartSample(5); // Bug here we get 1ms instead of 5ms
class11.StartSample(1);
class12.EndSample(5);
class11.PrintSample(); // Bug Here we get 15 ms period instead of 1ms
class11.EndSample(1);
}
}
}