代码之家  ›  专栏  ›  技术社区  ›  Vishnu Pradeep

如何中止在另一个函数中启动的线程?

  •  3
  • Vishnu Pradeep  · 技术社区  · 14 年前
    Monitor moni = new Monitor();
    Thread t = new Thread(() => moni.CurrUsage(nics,200));
    t.Start();
    

    我在“Form1_Load”函数中启动一个名为“t”的线程。我加了一个按钮。单击该按钮时,线程“t”应停止执行并使用这些参数创建一个新线程。

    Monitor moni = new Monitor();
    Thread t = new Thread(() => moni.CurrUsage(nics,950));
    t.Start();
    

    我知道在表单加载事件中我可以使用

    t.Abort();
    
    6 回复  |  直到 14 年前
        1
  •  5
  •   Joseph Tanenbaum    14 年前

    通过制作 t 作为表单的成员,您可以稍后在按钮单击事件处理程序中引用它。

    优雅的中止。 尽管 t.Abort() 完成任务后,线程中可能只剩下半个处理过的数据 t型 . 你可以抓住 ThreadAbortException 在线程中 t型 优雅地结束处理。

    小心重叠。 第二个问题是,您的线程可能还没有中止,而您的新线程已经启动。你可以打电话来阻止 t.Join() 打电话之后 t、 中止() .

    希望这有帮助。

        2
  •  2
  •   Stefan P.    14 年前

    制造 Thread t 你表格中的私人成员。

    public partial class MainForm : Form
    {
        private Thread t;
    }
    
        3
  •  1
  •   Evan Mulawski    14 年前

    一种方法是 Thread t 全局变量(位于Form_Load之外)。然后可以从该类中的任何方法访问和修改它。

    要实例化线程,请使用 t = new Thread(.... .

    在中止线程之前,请确保它不为空。

        4
  •  1
  •   Michael Shaw    14 年前

    您需要使线程对象在需要访问它的两个位置都可以访问。 在这种情况下,让它成为一个私有变量就行了。

    例如

    public class MyClass
    {
      private Thread MyThread
      {
        get;
        set;
      }
    
    
      private void myfunc1()
      {
        MyThread = new Thread(() => moni.CurrUsage(nics,200)); 
        MyThread.Start();
      }
    
      private void myfunc2()
      {
        MyThread.Abort();
    
        //  I really need to wait until this thread has stopped...
        MyThread.Join();
      }
    
    }
    
        5
  •  0
  •   Rudi    14 年前

    添加到已给出的答案:

    请注意 .Join() 将阻止当前(UI)线程,使应用程序对用户无响应。

    就像另一个观点:避免使用 .Abort() 如果可能的话,在监视器类中使用标志来退出正在执行的任务。你还可以等 .Join() ,但您可以完全控制后台线程中的状态。

    public class Monitor
    {
        private bool _cancel = false;
    
        public void Cancel()
        {
            _cancel = true;
        }
    
        public void CurrUsage(Nics nics, int n)
        { 
            _cancel = false;
            // ...
            while (!_cancel)
            {
            // do some stuff
            }
        }
    }
    

    以你的形式

    private Monitor _monitor { get; set; }
    private Thread _t;
    public void Button_Click(...)
    {
        _monitor.Cancel()
        _t.Join()       // will return as your background thread has finished cleanly
        _t = new Thread(() => _monitor.CurrUsage(nics,950));   
        t.Start();   
    }
    
        6
  •  0
  •   Adam Robinson    14 年前

    正如其他人所指出的,你所需要的一切 Abort 是对线程的引用(就像.NET中的任何其他对象一样)。

    然而

    你应该认真考虑重新考虑这种方法。一般来说,打电话 中止 不鼓励,因为它没有给目标线程足够的机会到达停止点。虽然有时是适当的(或唯一的选择),但 要停止的目标线程(通常通过 volatile bool 而不是像这样强迫。

    例如,

    public class ThreadClass
    {
        private volatile bool stopRequested;
        private Thread thread;
    
        public void Start()
        {
            stopRequested = false;
            thread = new Thread(ThreadMethod);
    
            thread.Start();
        }
    
        public void Stop()
        {
            stopRequested = true;
    
            if(!thread.Join(5000)) thread.Abort(); // forcefully abort if not 
                                                   // completed within 5 seconds
        }
    
        private void ThreadMethod()
        {
    
        }
    }
    

    然后你的代码进入 ThreadMethod . 在方法中,定期检查 stopRequested . 如果是真的,执行任何必要的清理(如果有的话),然后优雅地从线程中返回。如果内容是一个循环,则一般的做法是将检查放在循环的开始(假设循环足够紧)并且如果值为早,则退出。 true . 确切的位置实际上取决于代码,但一般的想法是,它应该经常被检查,以使线程在设置之后很快地退出,而不管发生什么时候。