zoukankan      html  css  js  c++  java
  • 多线程之BackgroundWorker组件

    多线程之BackgroundWorker组件

    2010-06-25  来自:新浪博客  字体大小:【  
    • 摘要:BackgroundWorker组件在多线程编程方面使用起来非常方便,然而在开始时由于没有搞清楚它的使用机制,走了不少的弯路,现在把我在使用它的过程中的经验与诸位分享一下。


    BackgroundWorker组件

    在VS2005中添加了BackgroundWorker组件,该组件在多线程编程方面使用起来非常方便,然而在开始时由于没有搞清楚它的使用机制,走了不少的弯路,现在把我在使用它的过程中的经验与诸位分享一下。
     

       BackgroundWorker类中主要用到的有这列属性、方法和事件:
        重要属性:
        1、CancellationPending             获取一个值,指示应用程序是否已请求取消后台操作。通过在DoWork事件中判断CancellationPending属性可以认定是否需要取消后台操作(也就是结束线程);
        2、IsBusy                          获取一个值,指示 BackgroundWorker 是否正在运行异步操作。程序中使用IsBusy属性用来确定后台操作是否正在使用中;
        3、WorkerReportsProgress           获取或设置一个值,该值指示BackgroundWorker能否报告进度更新
        4、WorkerSupportsCancellation      获取或设置一个值,该值指示 BackgroundWorker 是否支持异步取消。设置WorkerSupportsCancellation为true使得程序可以调用CancelAsync方法提交终止挂起的后台操作的请求;
        重要方法:
        1、CancelAsync         请求取消挂起的后台操作
        2、RunWorkerAsync      开始执行后台操作
        3、ReportProgress      引发ProgressChanged事件  
        重要事件:
        1、DoWork              调用 RunWorkerAsync 时发生
        2、ProgressChanged     调用 ReportProgress 时发生
        3、RunWorkerCompleted  当后台操作已完成、被取消或引发异常时发生
        另外还有三个重要的参数是RunWorkerCompletedEventArgs以及DoWorkEventArgs、ProgressChangedEventArgs。
        BackgroundWorker的各属性、方法、事件的调用机制和顺序:

    从上图可见在整个生活周期内发生了3次重要的参数传递过程:
        参数传递1:此次的参数传递是将RunWorkerAsync(Object)中的Object传递到 DoWork事件的DoWorkEventArgs.Argument,由于在这里只有一个参数可以传递,所以在实际应用往封装一个类,将整个实例化的类 作为RunWorkerAsync的Object传递到DoWorkEventArgs.Argument;
        参数传递2:此次是将程序运行进度传递给ProgressChanged事件,实际使用中往往使用给方法和事件更新进度条或者日志信息;
        参数传递3:在DoWork事件结束之前,将后台线程产生的结果数据赋给 DoWorkEventArgs.Result一边在RunWorkerCompleted事件中调用 RunWorkerCompletedEventArgs.Result属性取得后台线程产生的结果。
        另外从上图可以看到DoWork事件是在后台线程中运行的,所以在该事件中不能够操作用户界面的内容,如果需要更新用户界面,可以使用ProgressChanged事件及RunWorkCompleted事件来实现。


    在WinForm中经常遇到一些费时的操作界面,比如统计某个磁盘分区的文件夹或者文件数目,如果分区很大或者文件过多的话,处理不好就会造成“假死”的 情况,或者报“线程间操作无效”的异常,为了解决这个问题,可以使用委托来处理,在.net2.0中还可以用BackgroundWorker类。

    BackgroundWorker类是.net 2.0里新增加的一个类,对于需要长时间操作而不需要用户长时间等待的情况可以使用这个类。
    注意确保在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和 RunWorkerCompleted 事件与用户界面进行通信。
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;


    namespace BackgroundWorkerDemo
    {
    publicpartialclass MainForm : Form
    {
    private BackgroundWorker worker =new BackgroundWorker();
    public MainForm()
    {
    InitializeComponent();
    worker.WorkerReportsProgress
    =true;
    worker.WorkerSupportsCancellation
    =true;
    //正式做事情的地方
    worker.DoWork+=new DoWorkEventHandler(DoWork);
    //任务完称时要做的,比如提示等等
    worker.ProgressChanged +=new ProgressChangedEventHandler(ProgessChanged);
    //任务进行时,报告进度
    worker.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(CompleteWork);
    }

    //调用 RunWorkerAsync 时发生
    publicvoid DoWork(object sender, DoWorkEventArgs e)
    {
    e.Result
    = ComputeFibonacci(worker, e);//当ComputeFibonacci(worker, e)返回时,异步过程结束
    }
    //调用 ReportProgress 时发生
    publicvoid ProgessChanged(object sender, ProgressChangedEventArgs e)
    {
    this.progressBar1.Value = e.ProgressPercentage;
    }
    //当后台操作已完成、被取消或引发异常时发生
    publicvoid CompleteWork(object sender, RunWorkerCompletedEventArgs e)
    {
    MessageBox.Show(
    "完成!");
    }

    privateint ComputeFibonacci(object sender, DoWorkEventArgs e)
    {
    for (int i =0; i <1000; i++)
    {
    if (worker.CancellationPending)
    {
    e.Cancel
    =true;
    }
    else
    {
    worker.ReportProgress(i);
    }
    System.Threading.Thread.Sleep(
    10);
    }
    return-1;
    }

    privatevoid btnStart_Click(object sender, EventArgs e)
    {
    worker.RunWorkerAsync();
    btnStart.Enabled
    =false;
    btnPause.Enabled
    =true;
    }

    privatevoid btnPause_Click(object sender, EventArgs e)
    {
    btnPause.Enabled
    =false;
    btnStart.Enabled
    =true;
    worker.CancelAsync();
    }
    }
    }
     
     
    假如不让调用主线程控件,则load中:
    System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false;
     
     

    C#中BackgroundWorker概念详解及使用代码实现

    隶属于: IT » 语言基础 » C井
    点击展开 主题说明
    标题: C#中BackgroundWorker概念详解及使用代码实现
    [创建人] [被赞赏]0次 [被浏览]112次 [题下文章]1篇 [题下评论] 0
    点击展开 最佳文章顶一个
    文章列表加载中...
    文章列表加载中...
    作者信息读取中...
    [被赞赏]1次 [被浏览]1次 [评论] 0 [被挑战]N次 [日期]2012-07-02 11:43
    原创 子标题: BackgroundWorker的使用
    转载信息: http://blog.csdn.net/rrrrssss00/article/details/7707678

    一个程序中需要进行大量的运算,并且需要在运算过程中支持用户一定的交互,为了获得更好的用户体验,使用BackgroundWorker来完成这一功能.

     
    基本操作:
    bgw.RunWorkerAsync()        :
        开始后台运行执行,
        该函数后将触发bgw.DoWorker事件,需要执行的操作写在DoWorker事件响应函数里,
        该函数也可以加参数,参数从DoWorker事件处理函数的e.Arguement里获取
     
    bgw.CancelAsync()                :
        申请后台程序停止,
        注意该函数不能实际停止后台程序,只能将bgw的CancellationPending 值设为true,需要自己在后台运行的程序中判断这一值,进而停止后台程序的运行.
        注意本方法使用前,需要将bgw的WorkerSupportsCancellation 值设为true,否则将不起作用.
     
    bgw.ReportProgress()        :
        在后台程序中调用,向主线程传送进度信息,
        可以带一个或两个参数,一个为INT类型的进度(0~100),一个为自定义类型的参数,可以传任意信息.
        调用后,将触发bgw.ProgressChanged事件,可以将界面变化的代码写在该事件响应函数中,之前提到的两个参数均可从bgw.ProgressChanged事件响应函数的参数e中获取,分别为e.ProgressPercentage和e.UserState.    
        注意本方法使用前,需要将bgw的WorkerReportsProgress值设为true,否则将不会触发事件.

    开始后台运行:
    1. bgw= new BackgroundWorker();   
    2.           bgw.WorkerSupportsCancellation = true;  
    3.           bgw.WorkerReportsProgress = true;  
    4.   
    5.           bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);  
    6.           bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);  
    7.           bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);  
    8.   
    9.           bgw.RunWorkerAsync();  

    DoWork事件处理函数:
    1. void bgw_DoWork(object sender, DoWorkEventArgs e)   
    2.        {  
    3.            StartProgress();  
    4.   
    5.        }     

    WorkerCompleted事件处理函数(该函数在后台处理完成后被触发)
    1. void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)   
    2.        {  
    3.            MessageBox.Show("处理完成");  
    4.        }  

    ProgressChanged事件处理函数,
    1. void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)   
    2.        {  
    3.            if (e.UserState is int)  
    4.            {  
    5.                progressBar1.Value = (int)e.ProgressPercentage;  
    6.                label2.Text = e.UserState.ToString();  
    7.            }  
    8.            else if (e.UserState is List<object>)  
    9.            {  
    10.                List<object> tmp = (List<object>)e.UserState;  
    11.                progressBar1.Value = e.ProgressPercentage;  
    12.                label2.Text = tmp[0].ToString();  
    13.                this.label1.Text = tmp[1].ToString();  
    14.                this.listBox1.Items.Insert(0, tmp[2]);  
    15.            }  
    16.        }  

    后台运行的代码
    1.  private void StartProgress()           
    2. {  
    3.     //do sth  
    4.   
    5.     bgw.ReportProgress(per,paraInt);  

  • 相关阅读:
    python找出数组中第二大的数
    【高并发解决方案】5、如何设计一个秒杀系统
    如何找出单链表中的倒数第k个元素
    二叉树的前序,中序,后序遍历
    剑指Offer题解(Python版)
    python之gunicorn的配置
    python3实现字符串的全排列的方法(无重复字符)
    python实现斐波那契数列
    每天一个linux命令(56):netstat命令
    每天一个linux命令(55):traceroute命令
  • 原文地址:https://www.cnblogs.com/zhangjun1130/p/2636721.html
Copyright © 2011-2022 走看看