как приостановить/возобновить поток
Как приостановить / возобновить поток? Однажды Я ... --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.
это не лучшая идея вручную приостановить и возобновить потоки. Однако вы можете легко имитировать это поведение, используя примитивы синхронизации потоков (например,ManualResetEvent)
посмотри этот вопрос, вы можете найти его полезным.
но я считаю, что вы можете легко достичь своей цели "показывать случайный текст в элементе управления меткой" на временной основе с помощью таймеров.
вот краткий пример использования DispatcherTimer
var timer = new DispatcherTimer();
timer.Tick += (s, e) => Label.Text = GetRandomText();
timer.Interval = TimeSpan.FromMilliseconds(500);
timer.Start();
вы можете приостановить его, назвав timer.Stop()
а то timer.Start()
снова, чтобы возобновить.
вот два способа, которые сработали для меня. Оба предполагают, что рабочий поток имеет собственный цикл обработки.
- попросите поток вызвать обратный вызов, чтобы запросить разрешение на продолжение
- родитель вызвать метод класса потока сигнала
пример консольного приложения ниже показывает оба подхода, используя обратный вызов для приостановки / продолжения и рабочий метод для остановки. Другим преимуществом метода обратного вызова является то, что он также удобно для передачи обновлений состояния, когда он проверяет разрешение на продолжение.
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;
}
}
}