【问题标题】:What are alternative ways to suspend and resume a thread?有哪些替代方法可以暂停和恢复线程?
【发布时间】:2022-04-21 15:11:31
【问题描述】:

Thread.Suspend()Thread.Resume() 这两个方法自 .NET 2.0 起已过时。为什么?还有什么其他的选择和例子?

【问题讨论】:

    标签: c# .net-2.0 thread-safety


    【解决方案1】:

    您需要使用 AutoResetEvent EventWaitHandle。

    假设你想做这样的事情(注意:不要这样做!):

    private Thread myThread;
    
    private void WorkerThread() 
    {
        myThread = Thread.CurrentThread;
        while (true)
        {
            myThread.Suspend();
            //Do work.
        }
    }
    
    public void StartWorking() 
    {
        myThread.Resume();
    }
    

    正如其他人所说,这是一个坏主意。尽管仅在其自己的线程上使用 Suspend 相对安全,但您永远无法确定您是否在线程实际挂起时调用 Resume。所以 Suspend 和 Resume 已经过时了。

    相反,您想使用 AutoResetEvent:

    private EventWaitHandle wh = new AutoResetEvent();
    
    private void WorkerThread() 
    {
        while(true) 
        {
            wh.WaitOne();
            //Do work.
        }
    }
    
    public void StartWorking()
    {
        wh.Set();
    }
    

    工作线程将在等待句柄上等待,直到另一个线程调用 StartWorking。它的工作原理与暂停/恢复非常相似,因为 AutoResetEvent 只允许“恢复”一个线程。

    【讨论】:

    • 这解决了典型的挂起/恢复情况并避免了过时的警告。
    • 这意味着你必须把线程逻辑inside你的线程。暂停恢复允许您编写完全不知道任何线程的代码。
    • @zespri:呃,怎么样? Suspend()Resume()Thread 类的方法,你知道,它与线程有关。它们是不好的方法,原因与终止进程比要求停止更糟糕的原因相同。
    • @siride 您应该始终努力实现模块化。如果您可以编写代码,使您的工作线程不必进行任何线程管理并调用Thread 类上的任何方法,那么您已经做得很好了。将所有线程管理代码隔离在您的工作线程之外是理想的——不幸的是,这通常无法实现。 Suspend / Resume 特别是(曾经)是一种可能的情况。
    • @zespri:实际上,事件更抽象。 (1) 它们根本不必与线程一起使用。 (2) 他们回答了“某些条件是否为真,我可以继续进行?”的问题。无需参考是否设置了该条件。 (3) Suspend/Resume只能与线程一起使用,因此它们实际上根本没有提供线程抽象。
    【解决方案2】:

    所有好的替代方案都是在线程达到它乐于等待的点时工作的。挂起是危险的,因为它可能会在线程持有互斥锁时挂起线程 - 这是死锁的秘诀。

    因此,您的线程需要的是一个可以等待的 ManualResetEvent - 在它可以安全地这样做的时候,当它没有持有任何锁时。

    【讨论】:

    • ManualResetEvent 很好。您也可以使用 AutoResetEvent。
    【解决方案3】:

    这是有史以来最好的 Thread 教程(用于 C#):http://www.albahari.com/threading/

    等待你需要在线程上使用 .Join() 。这将等到胎面完成工作。否则,您将需要使用Wait/Pulse

    【讨论】:

      【解决方案4】:

      您可以使用 ManualReset 代替 AutoReset:

      public class Worker
      {
       ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
       ManualResetEvent _pauseEvent = new ManualResetEvent(true);
       Thread _thread;
      
      public Worker() { }
      
      public void Start()
       {
       _thread = new Thread(DoWork);
       _thread.Start();
       Console.WriteLine("Thread started running");
       }
      
      public void Pause()
       {
       _pauseEvent.Reset();
       Console.WriteLine("Thread paused");
       }
      
      public void Resume()
       {
       _pauseEvent.Set();
       Console.WriteLine("Thread resuming ");
       }
      
      public void Stop()
       {
       // Signal the shutdown event
       _shutdownEvent.Set();
       Console.WriteLine("Thread Stopped ");
      
      // Make sure to resume any paused threads
       _pauseEvent.Set();
      
      // Wait for the thread to exit
       _thread.Join();
       }
      
      public void DoWork()
       {
       while (true)
       {
       _pauseEvent.WaitOne(Timeout.Infinite);
      
      if (_shutdownEvent.WaitOne(0))
       break;
      
      // Do the work..
       Console.WriteLine("Thread is running");
      
       }
       }
      }
      

      【讨论】:

      • 试过了,没用。我在 _pauseEvent.WaitOne 行上放了一个断点,按 F10 后它移到下一行并继续运行线程。
      【解决方案5】:

      那个太长了。我需要的是一个快速的示例代码来使用。我从讨论中找到了一个,并由 Mark R. Dawson 在http://bytes.com/groups/net-c/458947-thread-suspend 回答。它解释了过时方法的危险以及如何使用 AutoResetEvent 通知第二个线程继续处理。

      【讨论】:

        【解决方案6】:

        我同意这是一个很棒的教程。 Suspend() 和 Resume() 过时的主要原因是它们是非常危险的方法。在任何时候 Thread t 都可以做任何事情。任何事物。想象一下,您的线程正在读取一个文件并对其进行了锁定。你暂停你的线程。文件保持锁定状态。任何其他资源也是如此。对互斥体的锁定也是如此。

        【讨论】:

          【解决方案7】:

          Thread.Suspend()Thread.Resume() 在 .NET 中已过时或被删除的原因与在 Java 中 Thread.suspend()Thread.resume() 已过时的原因大致相同。比较——

          【讨论】:

            【解决方案8】:

            解决方案: 如果另一个线程本身已挂起,则只有一个线程才能恢复另一个线程。 因此,第一个线程仅在另一个线程暂停自身(即其 ThreadState = Suspended)时才恢复另一个线程,从而使自己准备好恢复。这看起来安全无瑕。

            或者,我不了解 .Net 线程?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-03-24
              • 1970-01-01
              • 2010-12-28
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多