Подтвердить что ты не робот

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

Как приостановить/возобновить поток? Как только я Join() поток, я не могу его перезапустить. Итак, как я могу начать поток и сделать паузу всякий раз, когда нажата кнопка "пауза", и возобновить ее при нажатии кнопки возобновления?

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

4b9b3361

Ответ 1

Возможно, 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
   }
}

Ответ 2

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

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

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

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

SuspendRequested state

Ответ 3

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

Взгляните на этот вопрос, это может оказаться полезным.

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

Вот краткий пример, используя DispatcherTimer

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

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

Ответ 4

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

  • Попросите поток вызвать обратный вызов для запроса разрешения продолжать работу
  • Попросите родителя вызвать метод в классе потока, чтобы сообщить ему

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

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