我最近注意到.NET框架中的ManualResetEvent
類非常奇怪的行爲。我正在使用C#,VS 2015,項目的目標設置爲4.5.2。下面是完整的代碼:PC啓動後C#.NET ManualResetEvent的奇怪行爲
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
...
更重要的是,如果我在範圍16
改變!exit.WaitOne(25)
25
任何其他號碼31
,我得到了相同的結果:它等待31
毫秒。如果我選擇1
到15
範圍內的任何數字,它將精確等待16
毫秒。等等,如果我選擇32
到47
範圍內的任何標準,它就等於48
毫秒。但是:如果我編譯並運行這個代碼幾次(大約10-30)或者等待一段時間(大約5-20分鐘後啓動),它突然開始工作正常!是的,這聽起來很諷刺,但它會發生什麼。它以1 ms的精度開始阻塞精確給定時間的循環。它一直持續到下一臺電腦重新啓動。我在兩臺不同的PC上試過這個,並得到相同的行爲。谷歌搜索沒有給我這個問題絕對沒有。如果我運行沒有VS的編譯EXE,我會得到相同的行爲。
聽起來像它可能只是其啓動並修改某些後臺服務某些時點的時鐘精度。 –
「它突然開始工作正常」可能有一些其他程序提高了計時器分辨率。 Chrome做了一段時間。消耗電池。 – usr
可能是處理器時間的時間片放置在16ms的時間間隔內,以便在啓動時負載過重時在程序執行之間切換。一旦擁有更多的資源,它就能夠切換到需要處理時間的程序/線程。您可以檢查進程管理器(sysinternals)以查看系統或任務管理器上的負載以獲取有關負載的信息。 (我認爲編譯不是重點,而是編譯所需的時間)。一旦負載下降,請檢查您是否得到正確的結果。 – Uwe