none
用什么方法结束线程最号? RRS feed

答案

  • 你好!
         这个主要要看具体的应用场景,没有哪种方法可以适用于所有的场景!
         当然,主要还是使用Abort方法或Interrupt方法
         有时,需要和try...catch...finally结构配合,有时需要和join方法配合!
          主要考虑的问题并不是是否可以马上终止线程,而是怎样安装的终止线程,不对应用程序造成伤害!
        
    周雪峰
    2009年11月21日 16:57
    版主
  • 补充一点哈 join方法会等到线程执行完毕终止后,这会阻塞主线程


    Wenn ich dich hab’,gibt es nichts, was unerträglich ist.坚持不懈!My blog~~~
    2009年11月22日 2:56
    版主
  • 用 return 最好....

    要是你知道线程可能被终止的,就应该有终止的接口。
    2009年11月22日 7:29
  • 不推荐用 Abort 或者 Interrupt 来操作线程。这两个函数非常之 Evil。

    通常的,说一个编程习惯 Evil 意思是,这么做不好,不推荐这么做,除非没有其他的选择。

    为什么 Abort 和 Interrupt 这两个函数很 Evil?解释如下:

    它们的实现都是对被操作线程抛出一个异常。具体的说,Abort 是对被操作线程抛出一个 ThreadAbortException,Interrupt 则是抛出一个 ThreadInterruptException。

    麻烦之处在于,异常抛出的时间和地点都是不确定的,你不会知晓它们会在什么地方中断你的线程,也不会知道它们会造成什么结果。

    举个例子,假设你的线程正在朝数据库写入数据,突然被中断,那么结果便是只有一部分数据被写入数据库,剩余的部分没有被写入,而且程序员也不会知道哪些数据被写入了!

    再举个例子,假设你的线程对某个内核或者网络对象请求一个线程锁,然后恰巧该线程被异常终止或者中断了。很有可能你的线程无法释放线程锁,而导致死锁的产生。还有其他很多很多例子。


    比较好的一个编程习惯是让线程自己停下来。

    以我最近写的一个程序做例子吧。这是一个长时间后台运行的服务,进行某些操作,伪代码如下:

    internal class ServiceThread {
         private volatile bool shutdownRequestReceived = false;

         public void SendShutdownSignal() {
              this.shutdownRequestReceived = true;
         }

         private void ProcessDaemon() {
             while (!shutdownRequestReceived) {
                 call Biz();
                 Thread.sleep(SLEEP_INTERVAL);
             }     
         }
    }

    当主线程要求该服务线程被终止的时候,调用 SendShutdownSignal() 即可。该函数会把布尔量 shutdownRequestReceived 变成 true,这样 ProcessDaemon() 函数的循环便会停止。

    这是一种优雅的停止线程的方法。


    在更复杂的环境里面,当主线程告诉服务线程停止的时候,主线程有可能还需要等待服务器线程停止。
    考虑如下的一系列函数:

    internal class ServiceThread {
         public void SendShutdownSignal();
         public void WaitForShutdown();
         public void WaitForShutdown(TimeSpan timeout);
    }

    通过调用SendShutdownSignal(),主线程可以通知服务线程停止。
    通过调用WaitForShutdown(),主线程可以等待服务线程结束。

    注意WaitForShutdown函数有两个重载,第二个可以接受一个TimeSpan变量,当timeout发生的时候,主线程就通过调用 Abort() 会强制终止服务线程。这个时候才是使用 Abort() 的地方,因为没有其他选择了。


    WaitForShutdown() 可以很简单的用 Join 来实现:

    public void WaitForShutdown() {
        this.Join();
    }

    public void WaitForShutdown(TimeSpan timeout) {
        this.Join(timeout);
        this.Abort();
    }

    更复杂的等待可以用到信号量,这里就不阐述了。






    MCPD (Windows & Web)
    2009年11月22日 9:40
  • 线程里面也是个函数嘛,为啥不return非得Abort?

    2009年11月23日 9:33

全部回复

  • 你好!
         这个主要要看具体的应用场景,没有哪种方法可以适用于所有的场景!
         当然,主要还是使用Abort方法或Interrupt方法
         有时,需要和try...catch...finally结构配合,有时需要和join方法配合!
          主要考虑的问题并不是是否可以马上终止线程,而是怎样安装的终止线程,不对应用程序造成伤害!
        
    周雪峰
    2009年11月21日 16:57
    版主
  • 补充一点哈 join方法会等到线程执行完毕终止后,这会阻塞主线程


    Wenn ich dich hab’,gibt es nichts, was unerträglich ist.坚持不懈!My blog~~~
    2009年11月22日 2:56
    版主
  • 用 return 最好....

    要是你知道线程可能被终止的,就应该有终止的接口。
    2009年11月22日 7:29
  • 不推荐用 Abort 或者 Interrupt 来操作线程。这两个函数非常之 Evil。

    通常的,说一个编程习惯 Evil 意思是,这么做不好,不推荐这么做,除非没有其他的选择。

    为什么 Abort 和 Interrupt 这两个函数很 Evil?解释如下:

    它们的实现都是对被操作线程抛出一个异常。具体的说,Abort 是对被操作线程抛出一个 ThreadAbortException,Interrupt 则是抛出一个 ThreadInterruptException。

    麻烦之处在于,异常抛出的时间和地点都是不确定的,你不会知晓它们会在什么地方中断你的线程,也不会知道它们会造成什么结果。

    举个例子,假设你的线程正在朝数据库写入数据,突然被中断,那么结果便是只有一部分数据被写入数据库,剩余的部分没有被写入,而且程序员也不会知道哪些数据被写入了!

    再举个例子,假设你的线程对某个内核或者网络对象请求一个线程锁,然后恰巧该线程被异常终止或者中断了。很有可能你的线程无法释放线程锁,而导致死锁的产生。还有其他很多很多例子。


    比较好的一个编程习惯是让线程自己停下来。

    以我最近写的一个程序做例子吧。这是一个长时间后台运行的服务,进行某些操作,伪代码如下:

    internal class ServiceThread {
         private volatile bool shutdownRequestReceived = false;

         public void SendShutdownSignal() {
              this.shutdownRequestReceived = true;
         }

         private void ProcessDaemon() {
             while (!shutdownRequestReceived) {
                 call Biz();
                 Thread.sleep(SLEEP_INTERVAL);
             }     
         }
    }

    当主线程要求该服务线程被终止的时候,调用 SendShutdownSignal() 即可。该函数会把布尔量 shutdownRequestReceived 变成 true,这样 ProcessDaemon() 函数的循环便会停止。

    这是一种优雅的停止线程的方法。


    在更复杂的环境里面,当主线程告诉服务线程停止的时候,主线程有可能还需要等待服务器线程停止。
    考虑如下的一系列函数:

    internal class ServiceThread {
         public void SendShutdownSignal();
         public void WaitForShutdown();
         public void WaitForShutdown(TimeSpan timeout);
    }

    通过调用SendShutdownSignal(),主线程可以通知服务线程停止。
    通过调用WaitForShutdown(),主线程可以等待服务线程结束。

    注意WaitForShutdown函数有两个重载,第二个可以接受一个TimeSpan变量,当timeout发生的时候,主线程就通过调用 Abort() 会强制终止服务线程。这个时候才是使用 Abort() 的地方,因为没有其他选择了。


    WaitForShutdown() 可以很简单的用 Join 来实现:

    public void WaitForShutdown() {
        this.Join();
    }

    public void WaitForShutdown(TimeSpan timeout) {
        this.Join(timeout);
        this.Abort();
    }

    更复杂的等待可以用到信号量,这里就不阐述了。






    MCPD (Windows & Web)
    2009年11月22日 9:40
  • 感谢“隐约有歌”的回复啊!
    实际上当线程对自身调用 Abort 时,效果类似于引发异常;ThreadAbortException 会立刻发生,并且结果是可预知的。但是,如果一个线程对另一个线程调用 Abort ,则将中断运行的任何代码。
    并非所有情况下Abort方法都不可控制!当
    线程对自身调用 Abort 时,结果就是可 预知的!这时使用Abort就是合适的!
    当然,我们需要尽量让线程自己结束自己,这样可以让结束点可控!

    但是,在一些情况,我们还是需要让另外一个线程来强制结束本线程,这时就需要选择Abort方法了!
    Abort方法本身并不”邪恶“,但是需要在合适的场景,使用正确的方式来调用!
    另外, “隐约有歌”提到的信号量来通知线程结束,让线程自己结束自己的方法,在一些情况是比较”幽雅“,但是在另外一些情况下并不适用,这种方式会导致线程阻塞,如果你的要求就是需要线程等待,那这种方法就比较好,不然,容易带来一些副作用!
    周雪峰
    2009年11月22日 10:24
    版主
  • 线程里面也是个函数嘛,为啥不return非得Abort?

    2009年11月23日 9:33