【问题标题】:c# terminating a thread hangsc# 终止线程挂起
【发布时间】:2018-04-11 16:45:22
【问题描述】:

我已经查看了该主题的所有解决方案,但似乎仍然无法在不使用 Thread.Abort() 的情况下完成线程的停止。 下面是代码:创建线程的主类代码:

            _pollingThread = new Thread(pollingThread);
            _pollingThread.Start();

这里是线程:

 void _pollingThread()
 {
     while (continuePolling) //initially set to true
     {
          //do some things can take about 200ms to run
     }
 }

我接下来尝试通过将 continuePolling 设置为 false 来从主线程中停止线程。

 private void form1_FormClosing(object sender, FormClosingEventArgs e)
 {
     continuePolling = false;
     Thread.Sleep(1000);

     _pollingThread.Join(1000);

    if (_pollingThread.IsAlive) //always alive!
    {
        _pollingThread.Abort;
    }
 }

谁能告诉我我做错了什么? 谢谢

【问题讨论】:

  • continuePolling 在哪里以及如何定义?我认为您提供的代码不足以复制您遇到的问题。
  • 不要中止线程,使用同步原语告诉它离开。
  • 或使用thread.interupt
  • thread.Join 等待线程完成。你会挂在那里。您需要通过将 continuePolling 设置为 false 来告诉您的线程停止
  • @pm100 只在你不期望的时候使用异常

标签: c# multithreading winforms


【解决方案1】:

使用 Abort/Interrupt 来停止线程,是不好的编程。你永远不知道它做了什么,没有做什么。 有一个例外(比如终止挂起第 3 方代码),即使这样也认为它是邪恶的。您应该使用ManualResetEvent 告诉线程终止执行。 ManualResetEvent 是线程安全的,效果很好。

这是一个例子:

public class MyThread
{
    private ManualResetEvent _terminate = new ManualResetEvent(false);
    private Thread _thread;

    private void PollingThread()
    {
        while(!_terminate.WaitOne(0))
        {
            // do your stuff, if you want a pause after each loop,
            // you should change the 0 of waitone. This way the 
            // termination isn't blocked when waiting
        }
    }

    public MyThread()
    {
        _thread = new Thread(PollingThread);
        _thread.Start();
    }

    public void Stop()
    {
        if(_thread != null)
        {
            _terminate.Set();
            _thread.Join();
            _thread = null;
        }
    }
}

【讨论】:

  • 我刚试过这个。这没什么区别。连接永远不会发生。
  • 我使用这个模型已经很多年了,但它仍然像魅力一样工作。您的线程可能会挂在内部循环中或等待其他内容。你应该调试它。里面有没有永远的奔跑?它不应该..
  • 这很有趣...我用 Thread.Sleep(1000) 替换了线程中的所有内容,现在它可以正确连接了。
  • 这很有趣。我在一个读取串行端口的类中调用了一个方法,并且该调用总是快速运行。当我发出 _terminate.Set() 或 continuePolling = false 时,此调用永远不会返回。所以在你的例子中, PollingThread 会有一个像 data = BackEnd.Get_Data(); 这样的调用。这总是可以正常工作,但是一旦出现 _terminate.Set() 它就永远不会返回。为什么?串口类是静态类。
  • 我已将对串口类的直接访问更改为对另一个也访问串口的类的接口。没有更多的问题。感谢您的帮助。
【解决方案2】:

continuePolling 必须声明为volatile,否则无法保证一个线程中的修改会在任何其他线程中看到。

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/volatile

或者,您可以考虑使用System.Timers.Timer 之类的东西定期运行您的轮询操作。

【讨论】:

  • continuePolling 定义为 volatile bool continuePolling = true;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-22
  • 2014-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
相关资源
最近更新 更多