iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#线程间通信的异步机制
  • 255
分享到

C#线程间通信的异步机制

2024-04-02 19:04:59 255人浏览 安东尼
摘要

线程间通信 我们看下面的图 我们来看线程间通信的原理:线程(Thread B)和线程(Thread A)通信, 首先线程A 必须实现同步上下文对象(Synchronization

线程间通信

我们看下面的图

我们来看线程间通信的原理:线程(Thread B)和线程(Thread A)通信, 首先线程A 必须实现同步上下文对象(Synchronization Context), 线程B通过调用线程A的同步上下文对象来访问线程A,所有实现都是在同步上下文中完成的.线程B有两种方式来实现线程间的通信。

第一种:调用线程A的同步上下文对象,阻碍当前线程,执行红色箭头调用,直到黄色箭头返回(同步上下文执行完毕)才释放当前线程. (1->2->3->5)。

第二种:调用线程A的同步上下文对象(实际上是在开启一个新线程去执行,1->2->3->5) ,执行红色箭头,但并不阻碍当前线程(原有线程,1->4->5),绿色箭头继续执行。

文章中将会通过下面几个类来进行介绍:

  • ISynchronizeInvoke 接口
  • SynchronizationContext 类
  • AsyncOperation / AsyncOperationManager 类

1. ISynchronizeInvoke 接口

我们先来看下面一段异步的代码(Window FORM控件下有1个Button/1个Label),但点击Button的时候,执行异步调用,完成后,告诉Window Form的 Label控件Text属性”Asynchronous End”。

windows应用窗体应用程序中,对窗体上控件属性的任何修改都必须在主线程中完成。不能从其他线程安全地访问控件的方法和属性。

ISynchronizeInvoke 接口来自.net Framework 1.0,提供3个方法1个属性:

  • BeginInvoke / EndInvoke 方法 : 异步方法
  • Invoke 方法 : 同步方法
  • InvokeRequired 属性 : 判读来源的执行线程
        delegate void DoWork();
        private void button1_Click(object sender, EventArgs e)
        {
            //更新状态,添加到Listbox 中
            AddValue("Asynchronous Start.");
            //使用委托来调用异步方法
            DoWork work = DoWorkMethod;
            work.BeginInvoke(OnWorkCallback, work);
        }

        void OnWorkCallback(IAsyncResult asyncResult)
        {
            DoWork work = asyncResult.AsyncState as DoWork;
            if (work != null)
            {
                work.EndInvoke(asyncResult);
            }
            //(1)方法:调用Control控件的Invoke
            //Action<string> asyncUpdateState = UpdateStatus; //Action<string> 介绍=> 附1
            //Invoke(asyncUpdateState, "1:Asynchronous End.");

            //(2)方法:直接在异步调用的线程下
            UpdateStatus("2:Asynchronous End.");
        }

        void UpdateStatus(string input)
        {
            //把你需要通知的控件Control 赋值给ISynchronizeInvoke
            //来实现线程间的通信
            ISynchronizeInvoke async = this.listBoxStatus;
            //使用(1)方法,InvokeRequired == false ,来源当前(Window Form)主线程
            if (async.InvokeRequired == false)
                AddValue(input);
            else// 使用(2)方法 == true ,来源其他线程(异步)
            {
                Action<string> action = new Action<string>(status =>
                {
                    AddValue(status);
                });
                //调用ISynchronizeInvoke 提供的Invoke 同步方法,阻碍线程,直到调用结束
                //也可以使用ISynchronizeInvoke 提供的异步BeginInvoke/EndInvoke方法来实现调用.
                async.Invoke(action, new object[] { input });
            }
        }

        void AddValue(string input)
        {
            this.listBoxStatus.Items.Add(string.Format("[(#{2}){0}]Context is null:{1}", input, Thread.CurrentContext == null, Thread.CurrentThread.ManagedThreadId));
        }
        void DoWorkMethod()
        {
            Thread.Sleep(3000);//模拟耗时工作
        }

在代码中(UpdateStatus方法体内),我们可以看到主要是在ISynchronizeInvoke async = this.listBoxStatus;实现了线程间的通信,MSDN的解释” 实现此接口的对象可以接收事件已发生的通知,并且可以响应有关该事件的查询”. 并使Window Form(主线程) 下的ListBox 控件和来自异步方法(另外一个线程)的建立了通道。
InvokeRequired 判断线程的来源。

如果使用(1)方法,来源于Window Form 自身Control 的Invoke方法, InvokeRequired将返回false; 来源另外线程(异步)。

如果使用(2)返回true.同时ISynchronizeInvoke 提供了异步(BeginInvoke+EndInvok)和同步方法(Invoke)来实现线程间通信.Invoke 就是最上面的图1 所示的第一种 / BeginInvoke+EndInvok 是第二种。

2. SynchronizationContext 类

相比ISynchronizeInvoke 接口,SynchronizationContext 类(来自.Net Framework 2.0)提供了更多的方法来操作同步上下文对象,实现线程间通信.在上面的例子中SynchronizationContext类中将由 Post/Send 方法来实现。

反编译后我们看到:

  public virtual void Post(SendOrPostCallback d, object state)
 {
   ThreadPool.QueueUserWorkItem(new WaitCallback(d.Invoke), state);
 }

 public virtual void Send(SendOrPostCallback d, object state)
 {
   d(state);
 }
  • Send = ISynchronizeInvoke 中的Invoke 同步调用.图1中的第一种
  • Post = ISynchronizeInvoke 中的BeginInvoke + EndInvoke异步调用. 图1中的第二种

SynchronizationContext 类举例(在winform编程

      delegate void DoWork();
   private void button1_Click(object sender, EventArgs e)
   {
     //System.Windows.Forms.Form 自动的创建默认的同步上下文对象,
     //直接的获取当前的同步上下文对象
     SynchronizationContext context = SynchronizationContext.Current;
     //更新状态,添加到Listbox 中
     AddValue<string>("Asynchronous Start.");
     //使用委托来调用异步方法
      DoWork work = DoWorkMethod;
      work.BeginInvoke(OnWorkCallback, context);

    }
    void OnWorkCallback(IAsyncResult asyncResult)
    {
      AsyncResult async = (AsyncResult)asyncResult;
      DoWork work = (DoWork)async.AsyncDelegate;
      work.EndInvoke(asyncResult);
      
      //更新状态
      UpdateStatus("Asynchronous End.", asyncResult.AsyncState);
    }
    void UpdateStatus(object input,object syncContext)
    {
      //获取主线程(Window Form)中同步上下文对象
      SynchronizationContext context = syncContext as SynchronizationContext;
      //使用SynchronizationContext 类中异步Post 方法
      SendOrPostCallback callback = new SendOrPostCallback(p => {
        AddValue<object>(p);
      });
      context.Post(callback, input);//Post 为异步,Send 为同步

    }
    void AddValue<T>(T input)
    {
      this.listBoxStatus.Items.Add(string.Format("[(#{2}){0}]Context is null:{1}", input, Thread.CurrentContext == null, Thread.CurrentThread.ManagedThreadId));
    }
    void DoWorkMethod()
    {
      Thread.Sleep(3000);//模拟耗时工作
    }

上面我们已经说过在主线程中System.Windows.Forms.Form 自动的创建默认的同步上下文对象, 这时候我们把当前的同步上下文对象通过参数的形式赋值到异步线程中,调用Post 方法来实现, Post 方法接收 SendOrPostCallback 委托和额外object state参数,在Post方法体内调用线程池的线程来实现(Code2.1).当然我们也可以直接使用Send方法。

下面我们看看线程中的代码(在Console 下编程)。

  static class Program
 {
   static void Main()
   {
     Output("Main Thread Start.");
     //为主线程创建Synchronization Context
     var context = new SynchronizationContext();
     //开始一个新线程
     Thread threadB = new Thread(work);
      threadB.Start(context);

      Console.Read();
    }
    static void work(object context)
    {
      Output("Thread B");

      //获取主线程中的同步上下文对象
      SynchronizationContext sc = context as SynchronizationContext;

      //异步的方式和主线程通信,并发送"Hello World".
      sc.Post(new SendOrPostCallback(p =>
      {
        Output(p);
      }), "Hello World");
    }
    static void Output(object value)
    {
      Console.WriteLine("[ThreadID:#{0}]{1}", Thread.CurrentThread.ManagedThreadId, value);
    }
  }

在主线程中因为没有同步上下文对象,所以开始我们new SynchronizationContext(); 对象,其他和上面基本一样.此例说明了Post 是开启新线程(线程池)运行的。

3. AsyncOperation / AsyncOperationManager 类

AsyncOperation / AsyncOperationManager 类是SynchronizationContext 类的进一步封装和实现, AsyncOperationManager在创建AsyncOperation对象的时候会取得当前线程的同步上下文对象,并存储在AsyncOperation之中,使我们访问同步上下文对象更加容易。

  public class MySynchronizedClass
 {
   private AsyncOperation operation;
   public event EventHandler somethingHappened;
   public MySynchronizedClass()
   {
     //创建AsyncOperation 对象,并把当前线程的同步上下文保持到AsyncOperation中.
     operation = AsyncOperationManager.CreateOperation(null);

      Thread workerThread = new Thread(new ThreadStart(DoWork));
      workerThread.Start();
    }

    private void DoWork()
    {
      SendOrPostCallback callback = new SendOrPostCallback(state =>
       {
         EventHandler handler = somethingHappened;

         if (handler != null)
         {
           handler(this, EventArgs.Empty);
         }
       });

      operation.Post(callback, null);
      //注意1
      operation.OperationCompleted();
    }
  }

AsyncOperation类中实现了OperationCompleted的方法. SynchronizationContext 类中这个方法是没有具体的代码实现的。

到此这篇关于C#线程间异步通信的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: C#线程间通信的异步机制

本文链接: https://www.lsjlt.com/news/149645.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#线程间通信的异步机制
    线程间通信 我们看下面的图 我们来看线程间通信的原理:线程(Thread B)和线程(Thread A)通信, 首先线程A 必须实现同步上下文对象(Synchronization ...
    99+
    2024-04-02
  • C++详细分析线程间的同步通信
    目录1、多线程编程两个问题1.1、线程间的互斥1.2、线程间的同步通信2、生产者-消费者线程模型3、lock_gard和unique_lock4、流程分析1、多线程编程两个问题 1....
    99+
    2024-04-02
  • 怎么理解Java线程间通信与等待/通知机制
    本篇内容主要讲解“怎么理解Java线程间通信与等待/通知机制”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解Java线程间通信与等待/通知机制”吧!一、概念简介1、线程通信在操作系统中,线...
    99+
    2023-06-02
  • C#异步通信的示例分析
    这篇文章主要为大家展示了“C#异步通信的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C#异步通信的示例分析”这篇文章吧。C#异步通信概念及应用的认识首先让我们来看看:在网络编程中运用S...
    99+
    2023-06-17
  • Java学习之线程同步与线程间通信详解
    目录线程同步的概念同步代码块同步方法线程组线程组的相关方法线程组对象的基本应用线程间的通信线程通信简单应用线程同步的概念 由于同一个进程的多个线程共享同一块存储空间,在带来方便的同时...
    99+
    2022-12-27
    Java线程同步 Java线程通信 Java线程
  • python进程间的通信机制是什么
    本文小编为大家详细介绍“python进程间的通信机制是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“python进程间的通信机制是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。进程间通信表示进程之间的数...
    99+
    2023-07-05
  • Linux进程间通信机制有哪些
    Linux中的进程间通信机制有:1.管道,可用于具有亲缘关系进程间的通信;2.信号,用于通知接受进程有某种事件发生;3.消息队列,消息的链接表;4.共享内存,多个进程访问同一块内存空间;Linux中的进程间通信机制有以下几种管道管道是一种可...
    99+
    2024-04-02
  • C++线程间的互斥和通信场景分析
    目录互斥锁(mutex)模拟车站卖票不加锁的结果加锁后的结果简单总结条件变量(conditon_variable)生产者消费者线程模型产生问题解决问题原子类型(atomic)简单使用...
    99+
    2024-04-02
  • Java线程间通信方式
    前文了解了线程的创建方式和状态切换,在实际开发时,一个进程中往往有很多个线程,大多数线程之间往往不是绝对独立的,比如说我们需要将A和B 两个线程的执行结果收集在一起然后显示在界面上,又或者比较典型的消...
    99+
    2023-09-24
    java jvm 开发语言 android
  • c语言两个线程之间怎么通信
    在C语言中,可以使用以下方法实现两个线程之间的通信:1. 全局变量:两个线程可以共享一个全局变量,并通过对该变量的读写来进行通信。需...
    99+
    2023-10-12
    c语言
  • C++并发编程:如何处理线程间通信?
    c++++ 中线程间通信的方法包括:共享内存、同步机制(互斥锁、条件变量)、管道、消息队列。例如,使用互斥锁保护共享计数器:声明互斥锁(m)、共享变量(counter);每个线程通过加锁...
    99+
    2024-05-04
    c++ 并发编程 同步机制
  • android线程间怎么通信
    在Android中,线程间通信可以通过以下几种方式实现:1. Handler:可以通过Handler对象在不同的线程之间发送消息。每...
    99+
    2023-08-19
    android
  • C# 异步多线程入门到精通之Thread篇
    上一篇:C# 异步多线程入门基础 下一篇:C# 异步多线程入门到精通之ThreadPool篇 Thread API 这里对 Thread 的一些常用 API 进行介绍,使用一些案例进...
    99+
    2024-04-02
  • C#异步多线程入门到精通之ThreadPool篇
    上一篇:C# 异步多线程入门到精通之Thread篇 下一篇:异步多线程之入Task,待更新 启动线程池线程 ThreadPool 提供的 API 相对于 Thread 是比较少的,在...
    99+
    2024-04-02
  • Golang协程的通信机制
    go 协程通过通道(发送和接收数据)和同步原语(管理对共享资源的访问)进行通信。通道用于通过发送和接收操作在协程之间传输数据。同步原语包括互斥锁(控制对共享资源的访问)、条件变量(等待条...
    99+
    2024-04-16
    通信 协程 golang 并发访问
  • Java并发编程之线程间的通信
    目录一、概念简介1、线程通信2、等待通知机制3、基础方法二、等待通知原理1、基本原理2、实现案例三、管道流通信1、管道流简介2、使用案例四、生产消费模式1、业务场景2、代码实现五、源...
    99+
    2024-04-02
  • Python并发编程线程消息通信机制详解
    目录1 Event事件2 Condition3 Queue队列4 总结一下前面我已经向大家介绍了,如何使用创建线程,启动线程。相信大家都会有这样一个想法,线程无非就是创建一...
    99+
    2024-04-02
  • C++ BoostAsyncSocket如何实现异步反弹通信
    这篇文章主要介绍“C++ BoostAsyncSocket如何实现异步反弹通信”,在日常操作中,相信很多人在C++ BoostAsyncSocket如何实现异步反弹通信问题上存在疑惑,小编查阅了各式资料,整理出简单好用的...
    99+
    2023-07-05
  • 浅谈Java线程间通信方式
    目录1.volatile和synchronized关键字2.等待/通知机制3.管道输入/输出流4.join()方法5.ThreadLocal()方法总结线程间通信方式有两种:共享内存...
    99+
    2024-04-02
  • Golang与RabbitMQ实现多服务之间的异步通信
    要使用Golang与RabbitMQ实现多服务之间的异步通信,你需要按照以下步骤进行操作:1. 安装RabbitMQ:首先,你需要安...
    99+
    2023-10-08
    Golang
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作