我最近注意到.NET框架中ManualResetEvent
类的非常奇怪的行为。我使用的是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"));
}
}
}
}
}
我知道这可能听起来很愚蠢,但接下来会发生什么:如果我重新启动电脑,在启动后立即运行VS并运行此程序,我得到以下输出:
31.665
31.365
31.541
...
更重要的是,如果我将25
中的!exit.WaitOne(25)
更改为范围16
至31
中的任何其他数字,我会得到相同的结果:它等待{{1} }} 女士。如果我选择31
到1
范围内的任何数字,它会等待15
毫秒。依此类推,如果我选择16
到32
范围内的任何nuber,它会等待47
ms。
但是:如果我编译并运行此代码几次(大约10-30)或等待一段时间(启动后约5-20分钟),它突然开始正常工作!是的,这听起来很荒谬,但事情就是这样。它以1 ms的精度开始以精确的给定时间阻塞循环。它一直持续到下一次PC重启。我在两台不同的PC上试过这个并且得到了相同的行为。谷歌搜索给了我这个问题。如果我在没有VS的情况下运行编译的EXE,我会得到相同的行为。
答案 0 :(得分:1)
等待任何类型WaitHandle
保证等待至少与指定的超时一样长,但可能/可能更长。实际超时由系统时钟和系统繁忙程度决定。如果你想做精确计时WaitHandles或使用它们的类(例如ManualResetEvent
)不是要走的路。
答案 1 :(得分:-1)
我找到了答案 - 您可以致电TimeBeginPeriod
https://stackoverflow.com/a/15071477/1389883
或者您可以使用多媒体计时器API:https://stackoverflow.com/a/24843946/1389883