当前位置:网站首页 > 技术博客 > 正文

线程间怎么通信



    概述

    线程间通信指的是并发多线程间存在的数据交换行为,目前已支持ArkTS、C++等开发语言,因此存在不同语言、不同线程的通信场景,接下来详细展开介绍。

    同语言线程间通信(ArkTS内)

    • 场景描述

      ArkTS线程指的是包含ArkTS运行环境的线程,包括主线程、TaskPool线程、Worker线程。它们之间可以通过不同的接口进行通信。

    常见业务场景如下所示:

    常见业务场景 具体业务描述宿主JS线程<->TaskPool线程通过使用TaskPool,分发任务到子线程。TaskPool子任务与其宿主线程之间需要通信的场景宿主JS线程<->Worker线程通过使用Worker,启动子线程,执行任务。Worker子线程与其宿主线程之间需要通信的场景任意JS线程<->任意JS线程除了上述两种线程外,其他任意两个JS线程需要通信的场景
    • 实现方案介绍
    跨线程交互场景 通信方式 通信优先级宿主JS线程->TaskPool线程参数传递后分发任务;过程中不支持正向通信支持TaskPool线程->宿主JS线程结果返回;sendData触发宿主线程异步回调,底层为uv_async_send实现不支持宿主JS线程->Worker线程采用postMessage&onmessage异步通信不支持Worker线程->宿主JS线程异步方式:采用postMessage & onmessage异步通信
    同步方式:支持Worker线程同步调用宿主线程注册的方法,并返回结果不支持任意JS线程<->任意JS线程使用@ohos.emitter实现双向异步通信支持
    • 业务实现中的关键点
      ArkTS线程推荐使用TaskPool及Worker的原生接口通信。
    • 与业界方案特殊差异说明
      线程通信采用消息循环的机制,与业界一致。

    跨语言多线程通信(C++与ArkTS)

    • 场景描述
      ArkTS线程指的是包含ArkTS运行环境的线程,包括主线程、TaskPool线程和Worker线程。由于HarmonyOS支持通过Node-API开发C++业务,用户可以在C++层创建线程,因此C++线程存在与ArkTS线程通信的场景。

    常见业务场景如下所示:

    常见业务场景具体业务描述ArkTS线程(ArkTS)<->pthread线程ArkTS线程的ArkTS部分与pthread线程的通信场景ArkTS线程(C++)<->pthread线程ArkTS线程的C++部分与pthread线程的通信场景pthread线程<->pthread线程C++线程间的通信场景
    • 实现方案介绍

    • 案例参考
     
    
    • 与业界方案特殊差异说明
      1. Java与C++通信时,业界通过JNI调用,与Node-API机制比较类似。
      2. Java与C++通信时,业界支持C++线程通过attach方式直接反射调用Java方法,而HarmonyOS APP开发时需要通过napi_threadsafe_function异步通信。
    • 不推荐应用实现方式

    不建议为了同步调用,在C++层增加wait等机制,会导致卡死、掉帧等问题。

    线程间模块共享(单例模式)

    • 场景描述

    某些进程唯一的ArkTS实例初始化流程复杂,整体耗时长,放在主线程中对其进行初始化会造成应用启动耗时久和阻塞主线程的执行。将这些实例的初始化流程放在ArkTS子线程中进行初始化,初始化完成后主线程可以直接使用该实例。

    常见的业务场景如下所示:

    常见业务场景具体业务描述SDK初始化在ArkTS子线程中调用API的Init初始化得到一个单例对象,完成后传给其他ArkTS线程使用
    • 实现方案介绍(方案一)
      步骤一:采用C++单例模式封装,上层封装JS壳,子线程进行初始化;
      步骤二:初始化完成通知主线程,主线程导入使用该单例对象。

    • 业务实现中的关键点
    1. JS模块对象
      模块定义好的导出对象,也就是使用者Import时获得的模块对象。
      JS模块对象中的JS Function通过Node-API方法绑定至该模块的Native静态方法,调用时将调用Native静态方法来提供实际功能。
    2. Native Instance
      模块对象的成员对象(ExternalReference),由Native Class的GetCurrentInstance(标准单例实现)获得,进程内同模块都指向同一个Native单例。本设计对原有Native实现中已经提供线程安全的C++类的功能时使用,即该实例的Native成员方法也需进行同步保护。
      该模块对象即使有其它JS成员,也类似于”局部变量”,即线程间并不共享。
    3. Native静态方法
      Native静态方法提供对应模块的Native功能实现,通过napi_get_cb_info获取JS Binding Function的this对象,从而通过this获取绑定在JS模块对象上的Native Instance,再调用Native Instance对应的Native成员方法,即可完成对应功能实现。

    说明:
    同上,方法实现不可以进行全局变量的非线程安全操作。

    1. 生命周期问题

    一般模块对象在主线程退出时进行析构。

    若精细化控制,可绑定finalizeCallback进行管理,线程对象回收时会在该线程调用析构方法。

    • 案例参考
     
    
    • 实现方案介绍(方案二)
      步骤一:采用ArkTS原生对象,定义Sendable类的单例,封装成共享模块(进程内共享),子线程进行初始化;
      步骤二:初始化完成通知主线程,主线程导入使用该单例对象。
    • 案例参考
     
    
     
    
    • 与业界方案特殊差异说明

    Java存在ClassLoader机制,所有类型是静态且唯一的,因此可以很方便的导入类,支持单例模式。而HarmonyOS APP开发时需要借助共享模块,保证类只加载一次,保证唯一性。

    线程间不可变数据共享

    • 场景描述

    定义为Sendable类型的对象在发送到其他TS线程后可被多线程读写,开发者需要通过异步锁机制进行管理。需要一种能力保障对象的数据被多线程访问时准确,要么通过锁机制要么使对象变成只读对象。

    常见的业务场景如下所示:

    常见业务场景具体业务描述全局环境变量共享应用启动时生成一些资源加载入口、配置参数、全局变量等不需要更新的变量,可通过冻结能力冻结后共享到多个ArkTS子线程一次性产物不可变共享业务阶段性产生的页面布局数据,这个数据是在工作线程生成的,传输并缓存在UI线程后不会修改,可能会多次作为UI渲染的输入使用
    • 实现方案介绍
      通过冻结API,使共享对象变成只读对象。实现方案介绍:
      步骤一:业务逻辑定义、生成需要的Sendable对象;
      步骤二:发送到其他ArkTS线程前通过Object.Freeze API冻结该对象;
      步骤三:通过taskpool或worker的消息通信机制将该对象共享到其他ArkTS线程。
    • 业务实现中的关键
      冻结后对象不可修改,如果修改会抛出ArkTS异常。
    • 案例参考

    以全局环境变量共享为例:

     
    
     
    
     
    
    • 与业界方案特殊差异说明
      内存共享模型如JAVA/C++对象在不同线程间都是可见的,sendable对象(共享)需要将对象引用发送到其他线程才可使用。

    生产者与消费者模式

    • 场景描述
      生产者与消费者模式表现为以下几个特征:
      1. 有复数或单数个生产者并发地生产数据;
      2. 有复数或单数个消费者并发地消费数据;
      3. 存在一个数据缓存区,生产者生产出的数据存储在缓存区,消费者从缓存区中取数据,当缓存区满的时候要通知生产者停止生产,当缓存区为空时通知消费者休眠直到生产者添加数据。

    常见的业务场景如下所示:

    • 实现方案介绍

    以阅读应用场景为例:

    步骤一:用户一次翻页产生复数个前后页预加载的请求;

    步骤二:通过网络接口从云端下载复数页面的原始数据;

    步骤三:通过taskpool并发地解析每一页的页面原始数据生成page对象,page对象描述了页面的布局信息和每个组成部分;

    步骤四:taskpool执行的结果返回到UI线程的缓存队列中;

    步骤五:缓存队列中的页面数据中临近用户当前页的page对象执行渲染任务。

    • 业务实现中的关键
      1. 如果Page对象回到主线程只需要使用其中的数据可以考虑通过序列化在线程间传递,如果Page对象引用了复数个自定义类型的对象,为了将其完整地返回UI线程需要将其定义为Sendable类型的对象。
      2. 如果页面原始数据是TS线程间共享的,可以在UI线程执行下载任务(异步并发不阻塞UI线程),如果不是需要在taskpool工作线程中执行下载,避免线程间传递的耗时。
      3. 如果是对时延敏感的场景不建议使用并发模块处理相关逻辑,并发功能可以将负载从UI线程转移到工作线程但是会增加时延(并发不排队时大约500us)。
    • 与业界方案特殊差异说明
      1. 内存共享模型如JAVA/C++对象在不同线程间都是可见的,ArkTS是线程间内存隔离的内存模型对象在不同线程间使用需要序列化(拷贝),sendable对象(共享)需要将对象引用发送到其他线程才可使用。
      2. sendable对象存在较多约束,尽量只将必须共享的对象定义为sendable对象,由普通的ArkTS对象持有sendable对象并将整个流程串起来。

    总是有很多小伙伴反馈说:鸿蒙开发不知道学习哪些技术?不知道需要重点掌握哪些鸿蒙开发知识点? 为了解决大家这些学习烦恼。在这准备了一份很实用的鸿蒙全栈开发学习路线与学习文档给大家用来跟着学习。

    针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植……等)技术知识点。

    《鸿蒙 (Harmony OS)开发学习手册》(共计892页):

    如何快速入门?

    1.基本概念
    2.构建第一个ArkTS应用
    3.……

    在这里插入图片描述

    鸿蒙开发面试真题(含参考答案):

    在这里插入图片描述

    《OpenHarmony源码解析》:

    • 搭建开发环境
    • Windows 开发环境的搭建
    • Ubuntu 开发环境搭建
    • Linux 与 Windows 之间的文件共享
    • ……
    • 系统架构分析
    • 构建子系统
    • 启动流程
    • 子系统
    • 分布式任务调度子系统
    • 分布式通信子系统
    • 驱动子系统
    • ……

    图片

    OpenHarmony 设备开发学习手册:

    图片

  • 上一篇: xmlrpc-c
  • 下一篇: 前端上传文件流
  • 版权声明


    相关文章:

  • xmlrpc-c2024-12-15 11:30:03
  • 创建用户useradd命令如果要指定用户uid2024-12-15 11:30:03
  • json.parse解析字符串报错2024-12-15 11:30:03
  • usb驱动程序在哪里2024-12-15 11:30:03
  • 最大似然估计的不变性原理2024-12-15 11:30:03
  • 前端上传文件流2024-12-15 11:30:03
  • sqlserver char和varchar2024-12-15 11:30:03
  • jmap命令详解2024-12-15 11:30:03
  • img标签onerror2024-12-15 11:30:03
  • malloc函数2024-12-15 11:30:03