• C# 线程运行的机制和原理


      BackgroundWorker类可以简化线程在后台执行任务的工作,它具有以下几种主要成员:

      属性:WorkReportsProgress,WorkerSupportsCancellation,IsBusy;方法: RunWorkerAsync( ),CancellAsync( ),ReportProgress( );事件:DoWork,ProgressChanged,RunWorkerCompleted;这几种主要成员。

      WorkReportsProgress以及WorkerSupportsCancellation属性用于设置是否后台任务可以把进度汇报给主线程以及是否支持从主线程取消;IsBusy属性用来检查是否正在运行后台任务。

      3种事件用于发送不同的程序事件和状态;后台线程开始时触发Dowork事件,后台任务汇报状态的时候触发ProgressChanged事件,后台工作线程退出的时候触发RunWorkerCompleted事件。

      3种方法用于初始化行为或改变状态;调用RunWorkerAsync方法获取后台线程并且执行DoWork事件处理程序;调用CancelAsync方法把CancellationPending属性设置为True,虽不是必要的,但潜在的取消了线程,DoWork事件处理程序需要检查这个属性来决定是否应该停止处理;DoWork事件处理程序,在后台线程中如果希望向主线程汇报进度时,调用ReportProgress方法。

      这些事件处理程序的委托如下:每一个任务都有一个Object对象的引用作为第一个参数,以及EventArgs类的特定子类作为第二个参数。

      voidDoWorkEventHandler (object sender, DoWorkEventArgs e)

      voidProgressChangeEventHandler(object sender, ProgressChangeEventArgs e)

      voidRunWorkerCompletedEventHandler(object sender, RunWorkerCompletedEventArgs e)

      当为这些事件写附加事件处理程序时,应该如下来使用这些类。

      从创建BackgroundWorker类的对象并对它进行配置开始,如果希望工作线程为主线程汇报进度,需要把WorkReportsProgress属性设置为ture;如果希望从主线程取消工作线程,就把WorkerSupportsCancellation属性设置为true。

      设置好属性后,就可以通过调用RunWorkerAsync方法来启动它,它会开一个后台线程并发起DoWork事件处理后台程序。

      在主线程中,如果你已启用了WorkerSupportsCancellation属性,然后可以调用CancelAsync方法,它会设置CancellationPending的属性为true,我们需要在后台线程DoWork事件处理代码中检测这个属性。

      在后台线程继续执行任务时,要做以下几件事情:

      如果WorkReportsProgress属性为true并且后台线程要为主程序汇报进度的话,必须调用BackgroundWorker对象的ReportProgress方法,这时会触发主线程的ProgressChanged事件,从而运行相应的事件处理程序。

      如果WorkerSupportsCancellation属性为true,DoWork事件处理代码应该时时检测CancellationPending属性来确定是否已经取消,若是的话应该退出后台线程。

      如果后台线程没有取消,完成了其处理程序,则可以通过设置DoWorkEventArgs参数的Result字段来返回结果给主线程。

      在后台线程退出的时候会触发RunWorkerCompleted事件,其事件处理程序会在主线程上执行。RunWorkerCompletedEventArgs参数可以包含已完成后台线程的一些信息,比如返回值以及线程是否被取消了。

    代码实现如下:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Threading;
      4 using System.Linq;
      5 using System.Text;
      6 using System.ComponentModel;
      7  
      8 //线程实现原理
      9 namespace ConsoleApplication2
     10 {
     11     class DoBackgroundwork
     12     {
     13         BackgroundWorker bgWorker = new BackgroundWorker();
     14         public long BackgroundTotal {get; private set;}
     15         public bool CompletedNormally {get; private set;}
     16         
     17         //构造方法
     18         public DoBackgroundwork()
     19         {
     20             //设置BackgroundWorker属性
     21             bgWorker.WorkerReportsProgress = true;
     22             bgWorker.WorkerSupportsCancellation = true;
     23  
     24             //把处理程序连接到BackgroundWorker对象
     25             bgWorker.DoWork += DoWork_Handler;
     26             bgWorker.ProgressChanged += ProgressChanged_Handler;
     27             bgWorker.RunWorkerCompleted += RunWorkerCompleted_Handler;
     28         }
     29         public void StartWorker()
     30         {
     31             if(!bgWorker.IsBusy)
     32             {
     33                 bgWorker.RunWorkerAsync();
     34             }
     35         }
     36         
     37         public static long CalculateTheSequence(long value)
     38         {
     39             long total = 0;
     40             for(int i = 0; i < value; ++i)
     41             {
     42                 total += i;
     43             }
     44             return total;
     45         }
     46         public void DoWork_Handler(object sender, DoWorkEventArgs args)
     47         {
     48             BackgroundWorker worker = sender as BackgroundWorker;
     49             long total = 0;
     50             for(int i = 0; i <= 5; ++i)
     51             {
     52                 if(worker.CancellationPending)
     53                 {
     54                     args.Cancel = true;
     55                     worker.ReportProgress(-1);
     56                     break;
     57                 }
     58                 else
     59                 {
     60                     total += CalculateTheSequence(i * 10000000);
     61                     worker.ReportProgress(i * 20);
     62                     Thread.Sleep(300);
     63                 }
     64             }
     65             args.Result = total;
     66         }
     67         private void ProgressChanged_Handler(object sender, ProgressChangedEventArgs args)
     68         {
     69             string output = args.ProgressPercentage == -1
     70                 ? "   Cancelled"
     71                 : string.Format("               {0}%", args.ProgressPercentage);
     72             System.Console.WriteLine(output);
     73         }
     74         private void RunWorkerCompleted_Handler(object sender, RunWorkerCompletedEventArgs args)
     75         {
     76             CompletedNormally = !args.Cancelled;
     77             BackgroundTotal = args.Cancelled ? 0 : (long)args.Result;
     78         }
     79         public void Cancel()
     80         {
     81             if(bgWorker.IsBusy)
     82             {
     83                 bgWorker.CancelAsync();
     84             }
     85         }
     86     }
     87     class Program
     88     {
     89         static void Main(string[] args)
     90         {
     91             GiveInstructionsToTheUser();
     92             OutputTheSummaryHeaders();
     93             DoBackgroundwork bgw = new DoBackgroundwork();
     94             bgw.StartWorker();
     95             long mainTotal = 0;
     96             for (int i = 0; i < 5; ++i)
     97             {
     98                 if (Program.CheckForCancelInput())
     99                 {
    100                     bgw.Cancel();
    101                 }
    102                 mainTotal += DoBackgroundwork.CalculateTheSequence(100000000);
    103                 Thread.Sleep(200);
    104                 System.Console.WriteLine("     {0}%", (i + 1) * 20);
    105             }
    106             SummarizeResults(bgw, mainTotal);
    107             System.Console.ReadLine();
    108         }
    109         private static void GiveInstructionsToTheUser()
    110         {
    111             System.Console.WriteLine("Press <Enter> to start.");
    112             System.Console.ReadLine();
    113         }
    114         private static void OutputTheSummaryHeaders()
    115         {
    116             System.Console.WriteLine("   Main    Background ");
    117             System.Console.WriteLine("---------------------");
    118         }
    119         private static void SummarizeResults(DoBackgroundwork bgw, long mainTotal)
    120         {
    121             if (bgw.CompletedNormally)
    122             {
    123                 System.Console.WriteLine("\nBackground Completed Normally");
    124                 System.Console.WriteLine("Background Total = {0}.", bgw.BackgroundTotal);
    125             }
    126             else
    127             {
    128                 System.Console.WriteLine("\nBackground Cancelled.");
    129             }
    130             System.Console.WriteLine("Main Total ={0}.", mainTotal);
    131         }
    132         private static bool CheckForCancelInput()
    133         {
    134             bool doCancel = Console.KeyAvailable;
    135             if (doCancel)
    136             {
    137                 Console.ReadKey();
    138             }
    139             return doCancel;
    140         }
    141     }
    142 }

  • 相关阅读:
    ObjectARX 打印常见问题
    【动态规划】数字游戏(game)
    容斥原理在错排问题中的应用
    在某宝上用python抢茅台
    【笔记】Vue ElementPlus Rule 数字验证
    分布式中间件Nginx(一)
    20192419万腾阳 汇编程序设计 前四章学习笔记
    20192419 202120222 《网络与系统攻防技术》实验一实验报告
    reset.css 和 normalize.css
    reset.css 和 normalize.css
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/16494376.html
Copyright © 2020-2023  润新知