Как приостановить/возобновить поток
Как приостановить/возобновить поток? Как только я Join()
поток, я не могу его перезапустить.
Итак, как я могу начать поток и сделать паузу всякий раз, когда нажата кнопка "пауза", и возобновить ее при нажатии кнопки возобновления?
Единственное, что делает этот поток, - это показать некоторый случайный текст в элементе управления меткой.
Ответы
Ответ 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;
}
}
}