c#学习系列相关之多线程(三)----invoke和begininvoke

简介: c#学习系列相关之多线程(三)----invoke和begininvoke

一、invoke和BeginInvoke的作用

      invokebegininvoke方法的初衷是为了解决在某个非某个控件创建的线程中刷新该控件可能会引发异常的问题。说的可能比较拗口,举个例子:主线程中存在一个文本控件,在一个子线程中要改变该文本的值,此时会有可能引发异常。windows GUI编程有一个规则,就是只能通过创建控件的线程来操作控件的数据,否则就可能产生不可预料的结果。

二者的使用情况有两种:

1.在控件下应用,实例类型是个control例如button等;

2.在委托下进行使用,实例对象是一个委托类型,在使用时候会跳到当前线程。

invoke和begininvoke的区别:

1、Invoke() 调用时,Invoke会阻止当前主线程的运行,等到 Invoke() 方法返回才继续执行后面的代码,表现出“同步”的概念。

2、BeginInvoke() 调用时,当前线程会启用线程池中的某个线程来执行此方法,BeginInvoke不会阻止当前主线程的运行,而是等当前主线程做完事情之后再执行BeginInvoke中的代码内容,表现出“异步”的概念。在想获取 BeginInvoke() 执行完毕后的结果时,调用EndInvoke() 方法来获取。而这两个方法中执行的是一个委托。

二、Invke用法示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 线程test1005
{
    public delegate void test(string s1);
    class Program
    {
         static void Main(string[] args)
        {
            test tt = new test(t1);
            Thread thread = new Thread(() => {
                tt.Invoke("你好");
            });
            thread.Start();
            string obj = Thread.CurrentThread.ManagedThreadId.ToString();
            Console.WriteLine("主线程的ID" + " :" + obj);
            Console.Read();
        }
        static void t1(string s1)
        {
            string obj = Thread.CurrentThread.ManagedThreadId.ToString();
            Console.WriteLine(s1+"支线程的ID" +" :"+obj);
        }
    }


三、BeginInvoke用法示例

invoke和begininvoke对比:

1.invoke用法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 线程test1005
{
    public delegate void test(string s1);
    class Program
    {
         static void Main(string[] args)
        {
            test tt = new test(t1);
            tt.Invoke("你好");
 
            for (int i = 0; i < 300; i++)
            {
                Console.Write(3);
            }
            Console.Read();
        }
        static void t1(string s1)
        {
            for (int i = 0; i < 300; i++)
            {
                Console.Write(2);
            }
            string obj = Thread.CurrentThread.ManagedThreadId.ToString();
            Console.WriteLine(s1+"支线程的ID" +" :"+obj);
        }
    }
}

由结果可以看出invoke是依次按顺序向下执行;

2.beginInvoke用法:

首先介绍一下begininvoke的参数,其中作重要的就是后两个参数这里使用了BeginInvoke方法的最后两个参数,如果被调用的方法含有参数的话,这些参数将作为BeginInvoke的前面一部分参数,(就是 传入调用方法的参数)如果没有参数,BeginInvoke就只有两个参数。第一个参数是回调方法委托类型,这个委托只有一个参数,就是IAsyncResult,如MethodCompleted方法所示。当method方法执行完后,系统会自动调用MethodCompleted方法,传入的其实也是调用方法的返回类型,BeginInvoke的第二个参数需要向MethodCompleted方法中传递一些值,一般可以传递被调用方法的委托类型。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 线程test1005
{
    public delegate void test(string s1);
    class Program
    {
         static void Main(string[] args)
        {
            test tt = new test(t1);
            tt.BeginInvoke("111", (a) =>
            {
                for (int i = 0; i < 300; i++)
                {
                    Console.Write(1);
                }
            }, null);
            for (int i = 0; i < 300; i++)
            {
                Console.Write(3);
            }
            Console.Read();
        }
        static void t1(string s1)
        {
            for (int i = 0; i < 300; i++)
            {
                Console.Write(2);
            }
            string obj = Thread.CurrentThread.ManagedThreadId.ToString();
            Console.WriteLine(s1+"支线程的ID" +" :"+obj);
        }
    }
}

由运行结果可以知道,begininvoke可以继续执行调用方法后的函数,关于begininvoke的具体用法可以参考该文章:Delegate的BeginInvoke()_begininvoke参数-CSDN博客

例子:

static void Main(string[] args)
        {
   Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主  线程ID
            SayHello sayhello = new SayHello(Say);
            IAsyncResult iResult=sayhello.BeginInvoke("Olive",new AsyncCallback(Result), sayhello);//三个参数:1、Say()函数的参数,2、AsyncCallback类型的委托,(异步操作结束后执行的委托函数),3、将sayhello对象作为状态参数,在Result函数中会有用到该参数
     Console.ReadKey();
        }
         //AsyncCallback委托所执行的函数
        private static void Result(IAsyncResult iasyncresult)
        {
            SayHello sayhello = (SayHello)iasyncresult.AsyncState;//获取IAsyncResult对象的AsyncState的属性,即为Delegate.BeginInvoke()的第三个参数即sayhello。
            string s = sayhello.EndInvoke(iasyncresult);
            Console.WriteLine(s + "------好了,异步调用到这里已经结束了");
        }
        private static string  Say(string name)
        {
            Console.WriteLine("Hello!--------" + name);
            Console.WriteLine("当前的线程ID为:" + Thread.CurrentThread.ManagedThreadId);
            return "I Love you " + name;
        }

提示:1.begininvoke的返回值类型为IAsyncResult ,并且返回值会继续作为参数传入后续的AsyncCallback回调函数中Result。

2.函数的实际返回值需要通过EndInvoke进行获取!


相关文章
|
3月前
|
数据采集 XML JavaScript
C# 中 ScrapySharp 的多线程下载策略
C# 中 ScrapySharp 的多线程下载策略
|
2月前
|
安全 数据库连接 API
C#一分钟浅谈:多线程编程入门
在现代软件开发中,多线程编程对于提升程序响应性和执行效率至关重要。本文从基础概念入手,详细探讨了C#中的多线程技术,包括线程创建、管理及常见问题的解决策略,如线程安全、死锁和资源泄露等,并通过具体示例帮助读者理解和应用这些技巧,适合初学者快速掌握C#多线程编程。
78 0
|
3月前
|
安全 C# 开发者
【C# 多线程编程陷阱揭秘】:小心!那些让你的程序瞬间崩溃的多线程数据同步异常问题,看完这篇你就能轻松应对!
【8月更文挑战第18天】多线程编程对现代软件开发至关重要,特别是在追求高性能和响应性方面。然而,它也带来了数据同步异常等挑战。本文通过一个简单的计数器示例展示了当多个线程无序地访问共享资源时可能出现的问题,并介绍了如何使用 `lock` 语句来确保线程安全。此外,还提到了其他同步工具如 `Monitor` 和 `Semaphore`,帮助开发者实现更高效的数据同步策略,以达到既保证数据一致性又维持良好性能的目标。
47 0
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
43 1
C++ 多线程之初识多线程
|
23天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
17 3
|
23天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
16 2
|
23天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
28 2
|
23天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
28 1
|
23天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
33 1