как приостановить/возобновить поток

Как приостановить / возобновить поток? Однажды Я ... --0--> нить, я не могу перезапустить его. Итак, как я могу запустить поток и приостановить его при нажатии кнопки "пауза" и возобновить его при нажатии кнопки "возобновить"?

единственное, что делает этот поток, - это показать случайный текст в элементе управления label.

4 ответов


может быть 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
   }
}

Я мог бы предложить вам прочитать Threading in C#, by Joe Albahari, особенно приостановить и возобновить:

поток может быть явно приостановлен и возобновлен через поток устаревших методов.Suspend и Thread.Продолжить. Этот механизм полностью отделен от механизма блокировки. Обе системы независимы и работают параллельно.

поток может приостановить себя или другой поток. Вызов Suspend результатов в поток ненадолго переходит в состояние SuspendRequested, а затем, достигнув точки, безопасной для сбора мусора, переходит в состояние Suspended. Оттуда он может быть возобновлен только через другой поток, который вызывает его метод Resume. Resume будет работать только на приостановленном потоке, а не заблокированном потоке.

из .NET 2.0 приостановка и возобновление были устаревшими, их использование не рекомендуется из-за опасности, присущей произвольной приостановке другого потока. Если нить держит замок на критический ресурс приостановлен, все приложение (или компьютер) может взаимоблокировки. Это намного опаснее, чем вызов Abort - что приводит к тому, что любые такие блокировки освобождаются (по крайней мере теоретически) в силу кода в finally blocks.

SuspendRequested state


это не лучшая идея вручную приостановить и возобновить потоки. Однако вы можете легко имитировать это поведение, используя примитивы синхронизации потоков (например,ManualResetEvent)

посмотри этот вопрос, вы можете найти его полезным.

но я считаю, что вы можете легко достичь своей цели "показывать случайный текст в элементе управления меткой" на временной основе с помощью таймеров.

вот краткий пример использования DispatcherTimer

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

вы можете приостановить его, назвав timer.Stop() а то timer.Start() снова, чтобы возобновить.


вот два способа, которые сработали для меня. Оба предполагают, что рабочий поток имеет собственный цикл обработки.

  1. попросите поток вызвать обратный вызов, чтобы запросить разрешение на продолжение
  2. родитель вызвать метод класса потока сигнала

пример консольного приложения ниже показывает оба подхода, используя обратный вызов для приостановки / продолжения и рабочий метод для остановки. Другим преимуществом метода обратного вызова является то, что он также удобно для передачи обновлений состояния, когда он проверяет разрешение на продолжение.

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;
        }
    }
}