如何在c#中正确终止工作线程

Eld*_*Mor 7 c# multithreading

问题陈述

我有一个工作线程,基本上扫描文件夹,进入其中的文件,然后睡了一会儿.扫描操作可能需要2-3秒但不多.我正在寻找一种方法来优雅地阻止这个线程.

澄清:我想在线程休眠时停止线程,而不是在扫描时.但是,问题是我不知道线程的当前状态是什么.如果它正在睡觉我想让它立即退出.如果正在扫描,我希望它在尝试阻止的那一刻退出.

尝试解决方案

起初我正在使用睡眠和中断.然后我发现中断并没有真正中断睡眠 - 只有在线程TRIES进入睡眠状态时它才有效.

所以我切换到Monitor Wait&Pulse.然后我发现Pulse只在我实际上在等待时才有效.所以现在我有一个看起来像这样的线程:

while (m_shouldRun)
{
    try
    {
        DoSomethingThatTakesSeveralSeconds();
        lock (this)
        {
            Monitor.Wait(this, 5000);
        }
    }
    catch (ThreadInterruptedException)
    {
        m_shouldRun = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我需要制作我的Stop功能.所以我开始:

public void Stop()
{
    m_shouldRun = false;
    lock (this)
    {
        Monitor.Pulse(this);
    }
    thread.Join();
}
Run Code Online (Sandbox Code Playgroud)

但是这不起作用,因为我可能在线程工作时发出脉冲(虽然它没有等待).所以我添加了Interrupt:

public void Stop()
{
    m_shouldRun = false;
    thread.Interrupt();
    lock (this)
    {
        Monitor.Pulse(this);
    }
    thread.Join();
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用:

public void Stop()
{
    m_shouldRun = false;
    while (!thread.Join(1000))
    {
        lock (this)
        {
            Monitor.Pulse(this);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这个问题

什么是首选方法?有第三种方法更可取吗?

Dar*_*rov 9

优雅地停止线程的方法是让它自己完成.所以在worker方法中你可以有一个布尔变量来检查我们是否要中断.默认情况下,它将被设置为false,当您true从主线程设置它时,它将通过断开处理循环来停止扫描操作.

  • +1允许线程自行完成.任何其他方法都很混乱.不要忘记使用volatile关键字标记布尔标志. (3认同)
  • *您如何建议我从ThreadPool中获取一个实例并每10分钟运行一次扫描*:使用[ThreadPool.RegisterWaitForSingleObject](http://msdn.microsoft.com/en-us/library/system.threading. threadpool.registerwaitforsingleobject.aspx)方法并将`executeOnlyOnce`参数设置为false.当您解码为停止时,只需使用[RegisteredWaitHandle.Unregister](http://msdn.microsoft.com/en-us/library/system.threading.registeredwaithandle.unregister.aspx)取消注册等待句柄. (2认同)

lig*_*t78 8

另一种选择是使用事件:

private ManualResetEvent _event = new ManualResetEvent(false);


public void Run() 
{
 while (true)
 {
    DoSomethingThatTakesSeveralSeconds();
    if (_event.WaitOne(timeout))
      break;
 }
}

public void Stop() 
{
   _event.Set();
   thread.Join();
}
Run Code Online (Sandbox Code Playgroud)