如何暂停/恢复线程?一旦我执行了Join()
,就无法重新启动它。 所以当按下“暂停”按钮时,如何启动一个线程并使其暂停,并在按下继续按钮时恢复它?
该线程唯一的作用是在标签控件中显示一些随机文本。
如何暂停/恢复线程?一旦我执行了Join()
,就无法重新启动它。 所以当按下“暂停”按钮时,如何启动一个线程并使其暂停,并在按下继续按钮时恢复它?
该线程唯一的作用是在标签控件中显示一些随机文本。
也许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
}
}
线程可以通过已弃用的Thread.Suspend和Thread.Resume方法被显式地挂起和恢复。这个机制完全独立于阻塞机制。两个系统是独立的并且并行运行。
一个线程可以挂起自己或另一个线程。调用Suspend会导致线程暂时进入SuspendRequested状态,然后在到达对垃圾回收安全的点后进入Suspended状态。从那里,它只能通过另一个调用其Resume方法的线程来恢复。Resume只能在挂起的线程上工作,而不能在阻塞的线程上工作。
从.NET 2.0开始,Suspend和Resume已经被弃用,他们的使用不被鼓励,因为任意挂起另一个线程所固有的危险性。如果一个持有关键资源锁的线程被挂起,整个应用程序(或计算机)都可能死锁。这比调用Abort更危险 - 后者会导致任何这样的锁定通过finally块中的代码被释放(至少理论上如此)。
bool blocked = (someThread.ThreadState & ThreadState.WaitSleepJoin) != 0;
。那么为什么图表中没有区分呢?请参见此处。 - gliderkite以下是我使用过的两种方法。两种方法都假定工作线程有自己的处理循环。
下面的控制台应用程序示例展示了这两种方法,使用回调函数来暂停/继续,使用工作方法来停止。回调方法的另一个优点是,在检查是否有权限继续执行时,它也方便传递状态更新。
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;
}
}
}
KeepGoing()
方法传递给工作线程,因此该线程定期调用该方法与父对象进行检查,以查看是否应继续运行。工作线程不会每次重新启动 - 它只启动一次并一直运行,直到收到停止信号。 - Ed Power手动挂起和恢复线程并不是最好的选择。但是,您可以使用线程同步原语(如ManualResetEvent)轻松模拟此行为。
看一下这个问题,您可能会发现它有帮助。
但我相信您可以通过使用计时器轻松实现“按时间基础在标签控件中显示随机文本”的目标。
这里是一个使用DispatcherTimer的快速示例。
var timer = new DispatcherTimer();
timer.Tick += (s, e) => Label.Text = GetRandomText();
timer.Interval = TimeSpan.FromMilliseconds(500);
timer.Start();
您可以通过调用 timer.Stop()
来暂停它,然后再次调用 timer.Start()
来恢复。
DispatcherTimer
的代码在 GUI 线程上执行。如果您想要一个单独的线程,请使用 System.Threading.Timer
。 - TudorDispatcherTimer
就可以了,不会阻塞您的UI。 - Andrew Khmylov