PC 启动后 C# .NET ManualResetEvent 的奇怪行为
Strange behaviour of C# .NET ManualResetEvent after PC startup
我最近注意到 .NET Framework 中 ManualResetEvent
class 的行为非常奇怪。我正在使用 C#、VS 2015,项目的目标设置为 4.5.2。这是完整的代码:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace CSharpCOnsole
{
class Program
{
private static ManualResetEvent exit = new ManualResetEvent(false);
static void Main(string[] args)
{
var t = Task.Factory.StartNew(F);
Console.ReadKey();
exit.Set();
t.Wait();
exit.Close();
}
static void F()
{
var dtStopwatch = new Stopwatch();
uint ii = 0;
while (!exit.WaitOne(25)) {
dtStopwatch.Stop();
var dt = 1000.0 * dtStopwatch.ElapsedTicks / Stopwatch.Frequency;
dtStopwatch.Restart();
if (ii++ % 40 == 0) {
Console.WriteLine(dt.ToString("F3"));
}
}
}
}
}
我知道这听起来可能很愚蠢,但实际情况是这样的:如果我重新启动我的 PC,运行 VS 在启动后立即 运行 这个程序,我得到以下输出:
31.665
31.365
31.541
...
此外,如果我将 !exit.WaitOne(25)
中的 25
更改为 16
到 31
范围内的任何其他数字,我会得到相同的结果:它等待 31
女士。如果我选择 1
到 15
范围内的任何数字,它会等待 16
毫秒。依此类推,如果我选择 32
到 47
范围内的任何数字,它会等待 48
毫秒。
但是:如果我多次编译-运行 这段代码(大约 10-30 次)或等待一段时间(启动后大约 5-20 分钟),它突然开始正常工作!是的,这听起来很荒谬,但事实就是如此。它开始以 1 毫秒的精度在给定的确切时间阻塞循环。它一直持续到下一次 PC 重新启动。我已经在两台不同的 PC 上尝试过这个并且得到了相同的行为。谷歌搜索在这个问题上完全没有给我任何帮助。如果我 运行 在没有 VS 的情况下编译 EXE,我会得到相同的行为。
等待任何类型的 WaitHandle
保证等待 至少与指定的超时一样长 ,但可能/可能更长。实际超时由系统时钟和系统的繁忙程度决定。如果你想做精确计时 WaitHandles 或 类 使用它们(例如 ManualResetEvent
)不是要走的路。
我找到了答案 - 您可以通过调用 TimeBeginPeriod
来设置系统计时器的分辨率
或者您可以使用多媒体定时器API:
我最近注意到 .NET Framework 中 ManualResetEvent
class 的行为非常奇怪。我正在使用 C#、VS 2015,项目的目标设置为 4.5.2。这是完整的代码:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace CSharpCOnsole
{
class Program
{
private static ManualResetEvent exit = new ManualResetEvent(false);
static void Main(string[] args)
{
var t = Task.Factory.StartNew(F);
Console.ReadKey();
exit.Set();
t.Wait();
exit.Close();
}
static void F()
{
var dtStopwatch = new Stopwatch();
uint ii = 0;
while (!exit.WaitOne(25)) {
dtStopwatch.Stop();
var dt = 1000.0 * dtStopwatch.ElapsedTicks / Stopwatch.Frequency;
dtStopwatch.Restart();
if (ii++ % 40 == 0) {
Console.WriteLine(dt.ToString("F3"));
}
}
}
}
}
我知道这听起来可能很愚蠢,但实际情况是这样的:如果我重新启动我的 PC,运行 VS 在启动后立即 运行 这个程序,我得到以下输出:
31.665
31.365
31.541
...
此外,如果我将 !exit.WaitOne(25)
中的 25
更改为 16
到 31
范围内的任何其他数字,我会得到相同的结果:它等待 31
女士。如果我选择 1
到 15
范围内的任何数字,它会等待 16
毫秒。依此类推,如果我选择 32
到 47
范围内的任何数字,它会等待 48
毫秒。
但是:如果我多次编译-运行 这段代码(大约 10-30 次)或等待一段时间(启动后大约 5-20 分钟),它突然开始正常工作!是的,这听起来很荒谬,但事实就是如此。它开始以 1 毫秒的精度在给定的确切时间阻塞循环。它一直持续到下一次 PC 重新启动。我已经在两台不同的 PC 上尝试过这个并且得到了相同的行为。谷歌搜索在这个问题上完全没有给我任何帮助。如果我 运行 在没有 VS 的情况下编译 EXE,我会得到相同的行为。
等待任何类型的 WaitHandle
保证等待 至少与指定的超时一样长 ,但可能/可能更长。实际超时由系统时钟和系统的繁忙程度决定。如果你想做精确计时 WaitHandles 或 类 使用它们(例如 ManualResetEvent
)不是要走的路。
我找到了答案 - 您可以通过调用 TimeBeginPeriod
或者您可以使用多媒体定时器API: