有没有办法无限期地暂停一个线程?

Dan*_*ert 33 .net c# multithreading

我在空闲时间一直在使用网络爬行.NET应用程序,我想要包含的这个应用程序的一个功能是暂停按钮来暂停特定的线程.

我对多线程比较陌生,我无法找到一种无限期暂停线程的方法.我不记得确切的类/方法,但我知道有一种方法可以做到这一点,但它被.NET框架标记为已过时.

有没有什么好的通用方法可以无限期地暂停C#.NET中的工作线程.

我最近没有花很多时间来处理这个应用程序,最后一次触及它是在.NET 2.0框架中.我对.NET 3.5框架中存在的任何新功能(如果有的话)持开放态度,但是我想知道在2.0框架中也能工作的解决方案,因为这是我在工作中使用的,这对于知道以防万一.

Bra*_*non 93

永远不要使用Thread.Suspend.它的主要问题是99%的时间你暂停它时你不知道该线程正在做什么.如果该线程持有锁,则可以更容易进入死锁状态等.请记住,您调用的代码可能是在后台获取/释放锁.Win32有一个类似的API:SuspendThreadResumeThread.以下文档SuspendThread给出了API的危险性的一个很好的总结:

http://msdn.microsoft.com/en-us/library/ms686345(VS.85).aspx

此函数主要供调试器使用.它不适用于线程同步.如果调用线程尝试获取挂起线程拥有的同步对象,则在拥有同步对象(如互斥锁或临界区)的线程上调用SuspendThread会导致死锁.为了避免这种情况,应用程序中不是调试器的线程应该通知另一个线程暂停自身.目标线程必须设计为监视此信号并进行适当响应.

无限期挂起线程的正确方法是使用a ManualResetEvent.线程最有可能循环,执行一些工作.暂停线程的最简单方法是让线程在每次迭代时"检查"事件,如下所示:

while (true)
{
    _suspendEvent.WaitOne(Timeout.Infinite);

    // Do some work...
}
Run Code Online (Sandbox Code Playgroud)

您指定了无限超时,因此当未发出事件信号时,线程将无限期地阻塞,直到事件发出信号,此时线程将从中断处继续.

你会像这样创建事件:

ManualResetEvent _suspendEvent = new ManualResetEvent(true);
Run Code Online (Sandbox Code Playgroud)

true参数告诉事件以信号状态开始.

如果要暂停该线程,请执行以下操作:

_suspendEvent.Reset();
Run Code Online (Sandbox Code Playgroud)

并恢复线程:

_suspendEvent.Set();
Run Code Online (Sandbox Code Playgroud)

您可以使用类似的机制来指示线程退出并等待两个事件,检测哪个事件已发出信号.

为了好玩,我将提供一个完整的例子:

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

    public void Pause()
    {
        _pauseEvent.Reset();
    }

    public void Resume()
    {
        _pauseEvent.Set();
    }

    public void Stop()
    {
        // Signal the shutdown event
        _shutdownEvent.Set();

        // 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 here..
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*obe 16

C#电子书中的线程总结了Thread.Suspend和Thread.Resume:

不推荐使用的Suspend和Resume方法有两种模式 - 危险和无用!

本书建议使用同步构造(如AutoResetEventMonitor.Wait)来执行线程挂起和恢复.