Thread.Sleep(Timeout)とManualReseTevent.Wait(Timeout)の違いは何ですか?
-
24-10-2019 - |
質問
スレッド(タイムアウト)とresetevent.wait(タイムアウト)の両方が、少なくとも実行が一時停止します。 timeout
ミリ秒、それでそれらの間に違いはありますか? Thread.Sleepは、スレッドがその時間のスライスの残りの部分をあきらめることを知っています。 ManualReseTeventオブジェクトの待機(タイムアウト)メソッドには同じ問題がありますか?
編集: :ManualReseTeventの主なポイントは、別のスレッドから信号を送信することであることを知っています。現在、タイムアウトが指定されたイベントの待機方法の場合のみ関心があり、他の発信者はイベントを設定していません。スレッドよりも時間通りに目覚めた方が信頼できるかどうかを知りたい
解決
Thread.Sleep(timeout)
実行が再開される前に、無条件の待機を引き起こします。 resetEvent.WaitOne(timeout)
(1)イベントがトリガーされるか、(2)タイムアウトに到達するまで、スレッドが待機します。
イベントを使用するポイントは、別のスレッドからそれらをトリガーすることです。そのため、スレッドが目覚めたときに直接制御できます。これを必要としない場合は、イベントオブジェクトを使用してはいけません。
編集:タイミング面では、どちらも同様に信頼できます。しかし、「時間通りに目覚める」ことについてのあなたのコメントは私を心配しています。なぜあなたはあなたのコードが時間通りに目を覚ます必要があるのですか? Sleep
と WaitOne
精度を念頭に置いて実際に設計されていません。
場合にのみ timeout
50ミリ秒以下で、信頼性が必要です, 、タイミングの代替方法を調べる必要があります。 この記事 かなり良い概要のように見えます。
他のヒント
主な違い Thread.Sleep
と ManualResetEvent.WaitOne
ManulerReseTeventを待っているスレッドに信号を送ることができるということです。 設定 方法では、スレッドがタイムアウトよりも早く目覚めます。
あなたが信号を送らなければ、私は彼らが非常に似たように振る舞うことを期待します。
.NETリフレクターから、その方法がわかります ManualResetEvent.WaitOne
最終的には、次の署名を持つ外部メソッドへの呼び出しが行われます。
int WaitOneNative(SafeWaitHandle waitHandle,
uint millisecondsTimeout,
bool hasThreadAffinity,
bool exitContext);
一方 Thread.Sleep
この外部方法を呼び出します:
void SleepInternal(int millisecondsTimeout);
残念ながら、これらのメソッドのソースコードはありませんので、推測することしかできません。両方のコールで、タイムアウトが期限切れになるのを待っている間にスレッドがスケジュールされることを想像してください。どちらも他のものよりも特に正確ではありません。
遅延と周期学のために、私はモニターを見つけました。
object timelock = new object();
lock (timelock) { Monitor.Wait(timelock, TimeSpan.FromMilliseconds(X.XX)); }
これにより、優れた結果が得られます。...〜1msのジッター以上のアプリケーションの詳細に応じて。
すでに知っているかもしれませんが、shood.sleep(x)は信頼できず、キャンセルすることはできません。...ペストのように避けてください。
Sleep()関数は、このように長い間機能していません。その精度は、マルチメディアタイマー期間によって決定されます。これは、P/Inving TimeBeginPeriod()によって変更できるものです。残念ながら、私のマシンには、この期間を1ミリ秒に設定するプログラムがあり、睡眠がミリ秒まで正確になります。これがあなた自身のために試すためのいくつかのコードです:
using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
//timeBeginPeriod(1);
var sw1 = Stopwatch.StartNew();
for (int ix = 0; ix < 100; ++ix) Thread.Sleep(10);
sw1.Stop();
var sw2 = Stopwatch.StartNew();
var mre = new ManualResetEvent(false);
for (int ix = 0; ix < 100; ++ix) mre.WaitOne(10);
sw1.Stop();
Console.WriteLine("Sleep: {0}, Wait: {1}", sw1.ElapsedMilliseconds, sw2.ElapsedMilliseconds);
Console.ReadLine();
//timeEndPeriod(1);
}
[DllImport("winmm.dll")]
private static extern int timeBeginPeriod(int period);
[DllImport("winmm.dll")]
private static extern int timeEndPeriod(int period);
}
私のマシンの出力:
睡眠:999、待機:1003
約5ミリ秒のばらつきがあります。
他の人が言及したように、違いは、合図された場合、睡眠時間の前に戻ることができるという違いがあります。睡眠は睡眠時間を待つことが保証されています。
リフレクターコールでスリープ:スリープ:
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void SleepInternal(int millisecondsTimeout);
ManicalReseTevent.Wait in Reflector Call:
private static extern int WaitOneNative(SafeWaitHandle waitHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext);
2つの間に違いがあるかどうかはわかりませんが、何かを見つけることができるかどうかを確認します。
指定された時間の間睡眠は続きます。イベントが合図されれば、イベントの待機はより早く終了できます。これがイベントの目的です。あるスレッドが別のスレッドに目覚めさせるようにすることです。
1つのスレッドであなたは言うでしょう:
mre.WaitOne(10000); // ten seconds
Console.WriteLine("Woke up!");
別のことであなたは言うでしょう:
mre.Set(); // this causes `WaitOne` to return in the first thread
通話なし Set
他のスレッドでは、最初のスレッドは効果的に10秒間眠ります。