C#学习笔记之invoke与BeginInvoke

C#学习笔记之 invoke与BeginInvoke

​ 前段时间在写C#的上位机,用到invoke和BeginInvoke。前面对这两个的用法和原理比较模糊,这几天参考了网上的一些资料,整理如下笔记。

1.1 invoke与BeginInvoke介绍

invoke与BeginInvoke的两种使用情况:
1.control中的invoke、BeginInvoke
2.delegrate中的invoke、BeginInvoke
这两种情况是不同的,这里主要介绍第一种。dotNET中对invoke和BeginInvoke的官方定义如下:
control.invoke(参数delegate)方法:在拥有此控件的基础窗口句柄的线程上执行指定的委托
control.BeginInvoke(参数delegate)方法:在创建此控件的基础窗口句柄的线程上异步执行指定的委托
其中Control中的invoke和BeginInvoke的参数为delegate,委托的方法是在Control的线程上执行的,即UI线程。由定义我们可以知道invoke表示同步、Begininvoke表示异步

下面做一个测试:

新建一个UI工程,界面如下图1
测试界面

1.2 invoke分析:

invoke代段码如下:

        private void invoke_btn_Click(object sender, EventArgs e)
        {
       	    //主线程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "AAA");
            invokeThread = new Thread(new ThreadStart(StartMethod));
            invokeThread.Start();
            string ch = string.Empty;
            for(int ss = 0; ss < 3; ss++)
            {
                Thread.Sleep(1000);
                ch = ch + "B";
            }
            //主线程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + ch); 
        }

        private void StartMethod()
        {
            //子线程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "CCC");
            //提交到主线程
            invoke_btn.Invoke(new InvokeDelegate(invokeMethod));
            //子线程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "DDD");

        }

        private void invokeMethod()
        {
            //主线程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEE");
            
        }

​ 测试结果:双击运行exe,单击invoke,程序运行的界面:1AAA->3CCC和1BBB->1EEE->3DDD。(Debug模式下的HashCode可能不一样,但是运行的顺序是一样的)
​ 结果分析:单击invoke按钮后,执行invoke_btn_Click函数,主线程运行AAA,然后BBB和子线程CCC同时执行(这里用循环+延时,显示更加清楚),接着通过invoke来将invokeMethod方法提交给主线程,然后子线程等待主线程执行完毕(即等待EEE执行完成),最后执行子线程的DDD。

1.3 BeginInvoke分析:

BeginInvoke代段码如下:

		private void bginvoke_btn_Click(object sender, EventArgs e)
		{
		    //主线程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "AAA");
            bginvokeThread = new Thread(new ThreadStart(bgStartMethod));
            bginvokeThread.Start();
            string ch = string.Empty;
            for (int ss = 0; ss < 3; ss++)      
            {
                Thread.Sleep(1000);
                ch = ch + "B";
            }
            //主线程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + ch);
        }

        private void bgStartMethod()
        {
            //子线程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "CCC");
            //提交给主线程
            bginvoke_btn.BeginInvoke(new InvokeDelegate(bginvokeMethod));
            //子线程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "DDD");
            

        }

        private void bginvokeMethod()
        {	
        //主线程
         MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEE");
        }
    

​ 测试结果:双击运行exe,单击BeginInvoke,程序运行的界面:1AAA->3CCC和1BBB->1EEE和3DDD。(Debug模式下的HashCode可能不一样,但是运行的顺序是一样的)
结果分析:单击BeginInvoke按钮后,执行bginvoke_btn_Click函数,主线程运行AAA,然后BBB和子线程CCC同时执行,然后通过BeginInvoke来将bginvokeMethod方法提交给主线程,接着主线程执行EEE(主线程自己的任务完成),同时子线程继续执行DDD。

1.4对比分析

​ 通过上述两个测试可以发现:invoke和BeginInvoke提交的委托方法都是在主线程中执行的。但是invoke所提交的委托方法是(EEE)执行完毕后,才继续执行的DDD;而BeginInvoke提交的委托方法后,子线程可以继续执行DDD,不需要等待EEE执行完毕。因此在两者的使用方面是不同的,当后台线程在更新一个UI控件的状态后不需要等待,而是继续往下执行,此时宜用BeginInvoke来进行处理,如一边接收数据,将数据存入队列,一边对数据队列进行文本,曲线的更新;当后台线程需要操作UI控件,并且需要等待该操作执行完毕才能继续往下执行,此时宜用invoke来进行处理,如必须接收一帧立即处理一帧数据。

猜你喜欢

转载自blog.csdn.net/qq_18150255/article/details/83751291