私は空き時間に Web クロール .NET アプリの開発に取り組んでおり、このアプリに組み込みたい機能の 1 つに、特定のスレッドを一時停止する一時停止ボタンがありました。
私はマルチスレッドにあまり詳しくなく、現在サポートされているスレッドを無期限に一時停止する方法がわかりません。正確なクラス/メソッドは思い出せませんが、これを行う方法があることは知っていますが、.NET フレームワークによって廃止としてフラグが付けられています。
C# .NET でワーカー スレッドを無期限に一時停止する、汎用的な良い方法はありますか。
最近このアプリに取り組む時間があまりなく、最後に触ったのは .NET 2.0 フレームワークでした。.NET 3.5 フレームワークに存在する新しい機能 (もしあれば) は歓迎しますが、仕事で使用しているのが 2.0 フレームワークなので、念のため 2.0 フレームワークでも機能するソリューションを知りたいです。
ベストアンサー1
は絶対に使用しないでくださいThread.Suspend
。 の主な問題は、一時停止したときにそのスレッドが何をしているかが 99% わからないことです。そのスレッドがロックを保持していると、デッドロックなどの状況に陥りやすくなります。呼び出しているコードがバックグラウンドでロックを取得/解放している可能性があることに留意してください。Win32 には、 および という同様の API があります。SuspendThread
のResumeThread
次のドキュメントには、SuspendThread
API の危険性がわかりやすくまとめられています。
http://msdn.microsoft.com/en-us/library/ms686345(VS.85).aspx
この関数は、主にデバッガーで使用するために設計されています。スレッドの同期に使用するためのものではありません。ミューテックスやクリティカル セクションなどの同期オブジェクトを所有するスレッドで SuspendThread を呼び出すと、呼び出しスレッドが中断されたスレッドが所有する同期オブジェクトを取得しようとすると、デッドロックが発生する可能性があります。この状況を回避するには、デバッガーではないアプリケーション内のスレッドが、他のスレッドに自身を中断するようにシグナルを送信する必要があります。ターゲット スレッドは、このシグナルを監視して適切に応答するように設計する必要があります。
スレッドを無期限に停止する適切な方法は、 を使用することですManualResetEvent
。スレッドはおそらくループして、何らかの作業を実行しています。スレッドを停止する最も簡単な方法は、次のように、各反復でスレッドにイベントを「チェック」させることです。
while (true)
{
_suspendEvent.WaitOne(Timeout.Infinite);
// Do some work...
}
無限のタイムアウトを指定すると、イベントが通知されない場合、スレッドはイベントが通知されるまで無期限にブロックされ、イベントが通知された時点でスレッドは中断したところから再開されます。
次のようにイベントを作成します:
ManualResetEvent _suspendEvent = new ManualResetEvent(true);
パラメータtrue
は、イベントがシグナル状態で開始するように指示します。
スレッドを一時停止したい場合は、次の操作を行います。
_suspendEvent.Reset();
スレッドを再開するには:
_suspendEvent.Set();
同様のメカニズムを使用して、スレッドに終了の信号を送り、両方のイベントを待機し、どのイベントが信号を受けたかを検出できます。
楽しみのために完全な例を挙げます:
public class Worker
{
ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
ManualResetEvent _pauseEvent = new ManualResetEvent(true);
Thread _thread;
public Worker() { }
public void Start()
{
_thread = new Thread(DoWork);
_thread.Start();
}
public void Pause()
{
_pauseEvent.Reset();
}
public void Resume()
{
_pauseEvent.Set();
}
public void Stop()
{
// Signal the shutdown event
_shutdownEvent.Set();
// Make sure to resume any paused threads
_pauseEvent.Set();
// Wait for the thread to exit
_thread.Join();
}
public void DoWork()
{
while (true)
{
_pauseEvent.WaitOne(Timeout.Infinite);
if (_shutdownEvent.WaitOne(0))
break;
// Do the work here..
}
}
}