委托和多线程(一)

         定义:委托是一个类型安全的对象,它指向程序中另一个以后会被调用的方法(或多个方法)。通俗的说,委托是一个可以引用方法的对象,当创建一个委托,也就创建一个引用方法的对象,进而就可以调用那个方法,即委托可以调用它所指的方法。

委托的试用步骤:

1、定义委托:权限修饰符   delegate   返回值     委托名 (参数);

2、声明委托:  委托名 委托对象;

3、将对象与委方法绑定(可以绑定一个方法或者多个方法): 委托对象  = new 委托名(需要绑定的方法名称);

4、使用委托调用方法:委托实例名(参数);

Ps:1、委托和委托绑定的方法需要相同的参数(参数类型和个数都要相同)和返回值;

        2、委托可以调用多个方法,委托对象可以维护可调用方法的列表;即多路广播,简称:多播;

        3、使用+= 添加绑定方法,-=释放绑定方法;delegate委托可以不带参数,支持最大23个参数;可以没有返回值,也可以带返回值;

委托其中常见的写法有:

1、实例化委托并调用:委托名  委托实例 = new 委托名(委托方法);委托实例(参数);

2、实例化委托并调用 简写委托名  委托实例 = 委托的方法 ;委托实例(参数);

3、实例化委托并调用 匿名委托:委托名   委托实例 = delegate(参数){待调用的方法体};委托名(参数);

4、实例化委托并调用 lambda表达式写法:委托名  委托实例 = ((参数1,参数2,参数3,参数4,...参数n)=>{待调用的方法体});委托实例(参数1,参数2,参数3,...参数n);

5、在.NET 2.0开始 ,出现Func<in T,out TResult> 和Action<in T>

     Func至少0个参数,至多16个参数,必须有返回值

     Action至少0个参数,至多16个参数,无返回值。

     Func<参数1,参数2,...参数n,返回值> 委托实例 = ((参数1,参数2,。。。参数n)=>{带返回值的方法体});

     返回值 = 委托实例(参数1,参数2,。。。参数n);

     Action<参数> 委托实例 = ((参数)=>{待执行的方法体});委托实例(参数);

     Predicate<T>表示定义一组条件并确定指定对象是否符合这些条件的方法,返回值始终为bool类型

      申明的原型:  public delegate bool Predicate<in T>(T obj)  由于比较陌生;所以下面给一个事例:

      

1 public bool Match(int val)
2 {
3     return val > 60;
4 }
5     
6 Predicate<int> t = new Predicate<int>(Match);   //定义一个比较委托
7 int[] arr = { 13, 45, 26, 98, 3, 56, 72, 24 };            
8 int first = Array.Find(arr, t);                 //找到数组中大于60的第一个元素

  下面陆续介绍:

1、Invoke

2、BeginInvoke,EndInvoke

3、Thread

4、线程池

5、线程同步

6、死锁

7、线程同步的几种方法

8、在线程中访问GUI组件

Invoke:

      Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托。

      Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托。

 msdn说明:

      控件上的大多数方法只能从创建控件的线程调用。 如果已经创建控件的句柄,则除了 InvokeRequired 属性以外,控件上还有四个可以从任何线程上安全调用的方法,它们是:InvokeBeginInvokeEndInvoke 和 CreateGraphics。 在后台线程上创建控件的句柄之前调用 CreateGraphics 可能会导致非法的跨线程调用。 对于所有其他方法调用,则应使用调用 (invoke) 方法之一封送对控件的线程的调用。 调用方法始终在控件的线程上调用自己的回调。

      主线程调用Invoke:

1       public void TestInvoke()
2         {
3             listBox1.Items.Add("----Add------
");
4             listBox1.Invoke(new Action(() => { listBox1.Items.Add("Incoke"); }));
5             Thread.Sleep(1000);
6             listBox1.Items.Add("---End-----");
7         }

     主线程调用BeginInvoke:

1        public void TestInvoke()
2         {
3             listBox1.Items.Add("----Add------
");
4             var b = listBox1.BeginInvoke(new Action(() => { listBox1.Items.Add("BrginInvoke"); }));
5             Thread.Sleep(1000);
6             listBox1.Items.Add("---End-----");
7         }

只有当调用BeginInvoke的线程结束后,才执行它的内容。

不过有两种情况下,它会马上执行;1、使用EndInvoke,检索由传递的 IAsyncResult 表示的异步操作的返回值。2、同一个控件调用Invoke时,会马上执行先前的BeginInvoke

1、

 1  public void TestInvoke()
 2         {
 3             listBox1.Items.Add("----Add------
");
 4             var b = listBox1.BeginInvoke(new Action(() =>
 5             {
 6                 Thread.Sleep(1000);
 7                 listBox1.Items.Add("BrginInvoke");
 8             }));
 9             listBox1.EndInvoke(b);
10             listBox1.Items.Add("---End-----");
11         }

2.

 1  private void TestBeginInvokeInvoke()
 2         {
 3             listBox1.Items.Add("--begin--");
 4             listBox1.BeginInvoke(new Action(() =>
 5                 {
 6                     Thread.Sleep(1000);
 7                     listBox1.Items.Add("BeginInvoke");
 8                 }));
 9             listBox1.Invoke(new Action(() =>
10                 {
11                     listBox1.Items.Add("Invoke");
12                 }));
13             listBox1.Items.Add("--end--");
14         }

 注:在主线程中直接调用Invoke、BeginInvoke、EndInvoke都会造成阻塞。所以应该利用副线程(支线线程)调用

  • Invoke的委托在主线程中执行
  • Invoke在支线程中调用也会阻塞主线程
  • Invoke还会阻塞支线程
原文地址:https://www.cnblogs.com/QQ931697811/p/4351320.html