C# 如何暂停/恢复线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10469687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 13:58:59  来源:igfitidea点击:

how to pause/resume a thread

c#wpfmultithreadingresume

提问by Yustme

How can I pause/resume a thread? Once I Join()a thread, I can't restart it. So how can I start a thread and make it pause whenever the button 'pause' is pressed, and resume it when resume button is pressed?

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

The only thing this thread does, is show some random text in a label control.

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

采纳答案by Johannes Egger

Maybe the ManualResetEventis a good choice. A short example:

或许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
   }
}

回答by gliderkite

I could suggest you to read Threading in C#, by Joe Albahari, particularly Suspend and Resumesection:

我建议你阅读Joe Albahari 的 C# 线程,特别是Suspend 和 Resume部分:

A thread can be explicitly suspended and resumed via the deprecated methods Thread.Suspend and Thread.Resume. This mechanism is completely separate to that of blocking. Both systems are independent and operate in parallel.

A thread can suspend itself or another thread. Calling Suspend results in the thread briefly entering the SuspendRequested state, then upon reaching a point safe for garbage collection, it enters the Suspended state. From there, it can be resumed only via another thread that calls its Resume method. Resume will work only on a suspended thread, not a blocked thread.

From .NET 2.0, Suspend and Resume have been deprecated, their use discouraged because of the danger inherent in arbitrarily suspending another thread. If a thread holding a lock on a critical resource is suspended, the whole application (or computer) can deadlock. This is far more dangerous than calling Abort — which results in any such locks being released (at least theoretically) by virtue of code in finally blocks.

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

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

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

SuspendRequested state

暂停请求状态

回答by Andrew Khmylov

It's not the best idea to manually suspend and resume threads. However, you can easily simulate this behavior by using thread synchronization primitives (like ManualResetEvent)

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

Take a look at this question, you may find it helpful.

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

But I believe you can easily achieve your goal of 'showing random text in a label control' on a time basis by using timers.

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

Here is a quick example using DispatcherTimer

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

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

You can pause it by calling timer.Stop()and then timer.Start()again to resume.

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

回答by Ed Power

Here's two ways that's worked for me. Both assume that the worker thread has it's own processing loop.

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

  1. Have the thread invoke a callback to request permission to keep going
  2. Have the parent invoke a method on the thread's class to signal it
  1. 让线程调用回调来请求继续运行的权限
  2. 让父级调用线程类上的方法来向它发出信号

The console application example below shows both approaches, using a callback to pause/continue, and a worker method to stop. Another advantage of the callback method is that it's also convenient for passing back status updates while it's checking for permission to continue.

下面的控制台应用程序示例显示了两种方法,使用回调来暂停/继续,以及使用工作器方法来停止。回调方法的另一个优点是,在检查是否允许继续时,它也很方便地回传状态更新。

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