Invoke,BeginInvoke,EndInvoke

Invoke,BeginInvoke,EndInvoke

(一)使用规则

public IAsyncResult BeginInvoke(Delegate method);
public IAsyncResult BeginInvoke(Delegate method, params object[] args);

①:传递一个委托

this.BeginInvoke(new InvokeMethod(InvokeXXX), new object[] { listDgv });

public delegate void InvokeMethod(object x);
public void InvokeXXX(object x)
{
    dgvMain.DataSource = x;
}

②:传递系统委托  public delegate void Action<T>(T obj)

this.BeginInvoke(new Action(InvokeXXX), new object[] { listDgv });

③:传递匿名委托

④:传递无参委托

this.BeginInvoke(new Action(()=>{
    progressBar1.Value = 0;
}));

(二)BeginInvoke,EndInvoke在异步线程中的应用

2.1 线程概述

在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提供程序的性能,将要执行的任务分解成多个子任务执行。这就需要在同一个进程中开启多个线程。我们使用C#编写一个应用程序(控制台或桌面程序都可以),然后运行这个程序,并打开windows任务管理器,这时我们就会看到这个应用程序中所含有的线程数,如下图所示。

**:如果任务管理器没有“线程数”列,可以【查看】>【选择列】来显示“线程计数”列。从上图可以看出,几乎所有的进程都拥有两个以上的线程。从而可以看出,线程是提供应用程序性能的重要手段之一,尤其在多核CPU的机器上尤为明显。

image

2.2  用委托(Delegate)的BeginInvoke和EndInvoke方法操作线程
在C#中使用线程的方法很多,使用委托的BeginInvoke和EndInvoke方法就是其中之一。BeginInvoke方法可以使用线程异步地执行委托所指向的方法。然后通过EndInvoke方法获得方法的返回值(EndInvoke方法的返回值就是被调用方法的返回值),或是确定方法已经被成功调用。我们可以通过四种方法从EndInvoke方法来获得返回值。

image

关于BeginInvoke函数的分析:

image

**:在❶处有一个AsyncCallback的委托,该委托的定义为:public delegate void AsyncCallback(IAsyncResult ar),因此异步回调函数要以这个委托来进行签名调用。

BeginInvoke方法可启动异步调用。它与您需要异步执行的方法具有相同的参数,另外它还有两个可选参数。第一个参数是一个AsyncCallback 委托,该委托引用在异步调用完成时要调用的方法。第二个参数是一个用户定义的对象,该对象可向回调方法传递信息。BeginInvoke立即返回,不等待异步调用完成。BeginInvoke会返回IAsyncResult,这个结果可用于监视异步调用进度。

关于EndInvoke函数的分析:

image

EndInvoke方法检索异步调用的结果。调用BeginInvoke后可随时调用 EndInvoke 方法;如果异步调用尚未完成,EndInvoke 将一直阻止调用线程,直到异步调用完成后才允许调用线程执行。EndInvoke的参数包括您需要异步执行的方法的out和ref参数以及由BeginInvoke返回的IAsyncResult。

当我们Main()中加入Thread.Sleep(15000);等待15钟,再调用BeginInvoke(),任务管理器中线程数的变化如下图:说明在调用BeginInvoke()后系统会创建一个线程。

111

2.3 BeginInvoke和EndInvoke非阻塞式操作线程
如下图所示有这样一个UI,在执行某个耗时操作时,同时要在界面显示耗时操作运行的时间以告知终端用户。

12

代码实现namespace MyAsyncThreadWin
{
    public partial class Form1 : Form
    {
        int time = 1;
        public Form1()
        {
            InitializeComponent();
        }
        private string LongTimeTask()
        {
            Thread.Sleep(10000);
            return "执行完成";
        }
        private void Callback(IAsyncResult ar)
        {
            string str=(ar.AsyncState as Func<string>).EndInvoke(ar);
            this.timer1.Enabled = false;
            time = 1;
            this.label1.Text = str;
        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            Func<string> func = LongTimeTask;
            timer1.Enabled = true;
            IAsyncResult result = func.BeginInvoke(Callback,func);
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            label1.Text = "执行时间:" + time.ToString();
            time++;
        }
    }
}

代码分析:

(三)异步调用的异常处理过程。如下图产生的异常错误信息提示到终端用户。

333

代码实现namespace MyAsyncThreadWin
{
    public partial class Form1 : Form
    {
        int time = 1;
        public Form1()
        {
            InitializeComponent();
        }
        private string LongTimeTask()
        {
            try 
            {
                DataTable dt = null;
                dt.WriteXml("xxx.xml");
                Thread.Sleep(10000);
                return "执行完成";
            }
            catch (Exception)
            {
                Action<string> action = ExAction;                  this.timer1.Enabled = false;
                action("Error");                    return "Error";

            }
        }

        private void ExAction(string err)
        {
            MessageBox.Show(err);
        }
        private void Callback(IAsyncResult ar)
        {
            string str=(ar.AsyncState as Func<string>).EndInvoke(ar);
            this.timer1.Enabled = false;
            time = 1;
            this.label1.Text = str;
        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                Func<string> func = LongTimeTask;
                timer1.Enabled = true;
                IAsyncResult result = func.BeginInvoke(Callback, func);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            label1.Text = "执行时间:" + time.ToString();
            time++;
        }
    }
}

参考资料:

如何:对 Windows 窗体控件进行线程安全调用   https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2010/ms171728(v=vs.100)

 

 


 

 


 

 


 


 

posted @ 2018-01-03 13:59 李华丽 阅读( ...) 评论( ...) 编辑 收藏
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值