14

如何暂停/恢复线程?一旦我Join()一个线程,我就无法重新启动它。那么,如何在按下“暂停”按钮时启动线程并使其暂停,并在按下恢复按钮时恢复它?

该线程唯一做的就是在标签控件中显示一些随机文本。

4

4 回答 4

24

或许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
   }
}
于 2012-05-06T10:19:31.530 回答
7

我可以建议您阅读Joe Albahari 的 C# 中的线程,特别是暂停和恢复部分:

可以通过不推荐使用的方法 Thread.Suspend 和 Thread.Resume 显式挂起和恢复线程。这种机制与阻塞机制是完全分开的。两个系统都是独立的并且并行运行。

一个线程可以挂起自己或另一个线程。调用 Suspend 会导致线程短暂进入 SuspendRequested 状态,然后在达到垃圾收集安全点时,它进入 Suspended 状态。从那里,它只能通过另一个调用其 Resume 方法的线程来恢复。Resume 仅适用于挂起的线程,而不适用于阻塞的线程。

从 .NET 2.0 开始,Suspend 和 Resume 已被弃用,不鼓励使用它们,因为任意挂起另一个线程所固有的危险。如果持有关键资源锁的线程被挂起,整个应用程序(或计算机)可能会死锁。这比调用 Abort 危险得多——这会导致任何此类锁通过 finally 块中的代码被释放(至少在理论上)。

暂停请求状态

于 2012-05-06T10:18:07.390 回答
1

手动挂起和恢复线程不是最好的主意。但是,您可以通过使用线程同步原语(如ManualResetEvent)轻松模拟此行为

看看这个问题,你可能会发现它很有帮助。

但我相信您可以通过使用计时器轻松实现按时间“在标签控件中显示随机文本”的目标。

这是一个使用DispatcherTimer的快速示例

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

您可以通过调用暂停它timer.Stop(),然后timer.Start()再次恢复。

于 2012-05-06T10:21:50.750 回答
1

这里有两种对我有用的方法。两者都假设工作线程有自己的处理循环。

  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;
        }
    }
}
于 2012-05-07T18:12:34.210 回答