C#终止线程的方法

微软的文档中不建议以Abort的方式终止线程。比如终止线程的瞬间,FileStream没有释放,会出现问题,等等。

Framework4.0提供了标准取消模式:协作式取消(Cooperative Cancellation),工作线程会定期检查终止线程的标识。取消的时候,协作类中设置这个标识,然后等待工作线程响应。BackgroundWorker类中有类似的标识,可进行对比。

Demo 1:BackgroundWorker类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;
using System.ComponentModel;

namespace BackgroundWorkerDemo
{
    class Program
    {
        static BackgroundWorker bw; //namespace是 ComponentModel

        static void Main(string[] args)
        {
            bw = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };

            bw.DoWork += bw_DoWork; //将方法挂载到DoWork
            bw.RunWorkerCompleted += bw_RunWorkerCompleted; 


            bw.RunWorkerAsync();

            Console.ReadLine();
            if (bw.IsBusy) 
                bw.CancelAsync();

        }

        static void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            
            Console.WriteLine(e.Argument);

            Console.ResetColor();
            int i = 0;
            while(true)
            {
                if (bw.CancellationPending)
                {
                    e.Cancel = true; 
                    return;
                }
                
                bw.ReportProgress(i);
                i++;
                Thread.Sleep(100); 
                Console.WriteLine("DoWork progress: " + i.ToString());

                if (i == 5) //可以在工作线程中退出
                {
                    e.Cancel = true;
                    return;
                }
            }
        }

        static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                Console.WriteLine("you canceled,the progress quits");
                
            }
            else if (e.Error != null)
            {
                Console.WriteLine("Worker exception:" + e.Error.ToString());
            }
            else
            {
                Console.WriteLine("Complete :" + e.Result);
            }
        }
    }
}

Demo 2 :开启启两个线程,分别向对应文本框中添加信息

C#终止线程的方法_第1张图片

        private void button4_Click(object sender, EventArgs e)// 线程的终止,不建议使用Abort
        {
            //第一种方法:Abort 终止线程
            //if (AddThread.IsAlive && AddThread != null)
            //{
            //    AddThread.Abort();
            //}
            //if (AddThread2nd.IsAlive && AddThread2nd != null)
            //{
            //    AddThread2nd.Abort();
            //}


            //第二种方法
            canceler.Cancel();
            canceler2nd.Cancel();
            canceler.Token.Register(() =>
            {
                MessageBox.Show("工作线程被终止");
            });

            Thread1st = null;
            AddThread2nd = null;
        }
有一个问题,快速点击start和stop,线程停止没有问题,但是有时候却只开启了一个线程。可能是因为IsCancellationRequested的值没有及时更新为false。
参考https://blog.gkarch.com/threading/part3.html中第4部分的内容,写个线程终止类,代码如下:

class RulyCanceler
{
    readonly object _locker = new object();
    bool cancelRequest = false;
    bool IsCancellationRequest
    {
        get
        {
            lock (_locker)
            {
                return cancelRequest;
            }
        }
    }

    public void Cancel()
    {
        lock (_locker)
        {
            cancelRequest = true;
        }
    }

    public void Resume()
    {
        cancelRequest = false;
    }

    public void ThrowIfCancellationRequested()
    {
        if (IsCancellationRequest)
        {
            throw new OperationCanceledException();
        }
    }
}
            try
            {
                while (true)
                {
                    canceler.ThrowIfCancellationRequested();


                    Thread.Sleep(10);
                    AddHandleNew(i);
                    i++;


                }
            }
            catch (OperationCanceledException)
            {
                canceler.Resume();
                return;
            }
Resume需要放在catch(OperationCanceledException)中,也就是说catch到取消事件后,要将类中的取消标记置为false。这样才能避免反复点击start和stop出问题。



你可能感兴趣的:(【C#】)