web-dev-qa-db-ja.com

スレッドを一時停止/再開する方法

スレッドを一時停止/再開するにはどうすればよいですか?スレッドをJoin()すると、再起動できません。では、どのようにしてスレッドを開始し、「一時停止」ボタンが押されるたびにスレッドを一時停止させ、再開ボタンが押されたときにスレッドを再開させることができますか?

このスレッドが行う唯一のことは、ラベルコントロールにランダムテキストを表示することです。

14
Yustme

多分ManualResetEventが良い選択です。短い例:

private static EventWaitHandle waitHandle = new ManualResetEvent(initialState: true); 

// Main thread
public void OnPauseClick(...) {
   waitHandle.Reset();
}

public void OnResumeClick(...) {
   waitHandle.Set();
}

// Worker thread
public void DoSth() {
   while (true) {
     // show some random text in a label control (btw. you have to
     // dispatch the action onto the main thread)
     waitHandle.WaitOne(); // waits for the signal to be set
   }
}
21
Johannes Egger

C#でのスレッディング、Joe Albahariによる 、特に Suspend and Resume セクションを読むことをお勧めします。

スレッドは、非推奨のメソッドThread.SuspendおよびThread.Resumeを使用して明示的に中断および再開できます。このメカニズムは、ブロッキングのメカニズムとは完全に異なります。どちらのシステムも独立しており、並行して動作します。

スレッドは、それ自体または別のスレッドを中断できます。 Suspendを呼び出すと、スレッドが一時的にSuspendRequested状態になり、ガベージコレクションの安全なポイントに到達すると、Suspended状態になります。そこから、Resumeメソッドを呼び出す別のスレッドを介してのみ再開できます。再開は、中断されたスレッドではなく、中断されたスレッドでのみ機能します。

.NET 2.0以降では、SuspendとResumeは非推奨になりました。別のスレッドを勝手に中断することには危険が伴うため、その使用は推奨されません。重要なリソースのロックを保持しているスレッドが中断されると、アプリケーション全体(またはコンピューター)がデッドロックする可能性があります。これは、Abortを呼び出すよりもはるかに危険です。その結果、最終的にブロック内のコードにより、そのようなロックが(少なくとも理論的には)解放されます。

SuspendRequested state

6
gliderkite

スレッドを手動で一時停止および再開することは最善の方法ではありません。ただし、スレッド同期プリミティブ( ManualResetEvent など)を使用すると、この動作を簡単にシミュレートできます。

この質問 を見てください。参考になるかもしれません。

しかし、タイマーを使用すると、「ラベルコントロールにランダムなテキストを表示する」という目標を簡単に達成できると思います。

DispatcherTimer を使用した簡単な例を次に示します

_var timer = new DispatcherTimer(); 
timer.Tick += (s, e) => Label.Text = GetRandomText(); 
timer.Interval = TimeSpan.FromMilliseconds(500); 
timer.Start();
_

timer.Stop()を呼び出し、次にtimer.Start()を呼び出して一時停止して再開できます。

2
Andrew Khmylov

ここに私のために働く2つの方法があります。どちらも、ワーカースレッドに独自の処理ループがあると想定しています。

  1. スレッドにコールバックを呼び出して、続行する許可を要求する
  2. 親にスレッドのクラスのメソッドを呼び出して通知する

以下のコンソールアプリケーションの例は、コールバックを使用して一時停止/続行、ワーカーメソッドを使用して停止する両方のアプローチを示しています。コールバックメソッドのもう1つの利点は、続行の許可をチェックしているときに、ステータスの更新を返すのにも便利なことです。

using System;
using System.Threading;

namespace ConsoleApplication7
{
    class Program
    {
        static bool keepGoing;
        static void Main(string[] args)
        {
            keepGoing = true;
            Worker worker = new Worker(new KeepGoingDelegate(KeepGoing));
            Thread thread = new Thread(worker.DoWork);
            thread.IsBackground = true;
            thread.Start();

            while (thread.ThreadState != ThreadState.Stopped)
            {
                switch (Console.ReadKey(true).KeyChar)
                {
                    case 'p':
                        keepGoing = false;
                        break;
                    case 'w':
                        keepGoing = true;
                        break;
                    case 's':
                        worker.Stop();
                        break;
                }
                Thread.Sleep(100);
            }
            Console.WriteLine("Done");
            Console.ReadKey();
        }

        static bool KeepGoing()
        {
            return keepGoing;
        }
    }

    public delegate bool KeepGoingDelegate();
    public class Worker
    {
        bool stop = false;
        KeepGoingDelegate KeepGoingCallback;
        public Worker(KeepGoingDelegate callbackArg)
        {
            KeepGoingCallback = callbackArg;
        }

        public void DoWork()
        {
            while (!stop)
            {
                Console.Write(KeepGoingCallback()?"\rWorking":"\rPaused ");

                Thread.Sleep(100);
            }
            Console.WriteLine("\nStopped");
        }

        public void Stop()
        {
            stop = true;
        }
    }
}
1
Ed Power