【鸿蒙南向实战开发实例】OpenHarmony多线程能力场景化示例

前言

2024年可谓至关重要,而生态建设的前提,就是要有足够的开发人才。与之对应的,今年春招市场上与鸿蒙相关岗位和人才旺盛的热度,一方面反应了鸿蒙生态的逐渐壮大,另一方面也让人们对鸿蒙下一阶段的发展更具信心。
随着鸿蒙市场份额的不断提升,相应的岗位也会迎来一个爆发式的增长。这对于想要换赛道的程序员来说是一个非常好的消息,话说大家最近有想法转型鸿蒙开发吗?

简介

在OpenHarmony应用中,每个 进程 都会有一个主线程,主线程主要承担执行UI绘制操作、管理ArkTS引擎实例的创建和销毁、分发和处理事件、管理Ability生命周期等职责,具体可参见 线程模型概述 。因此,开发应用时应当尽量避免将耗时的操作放在主线程中执行。ArkTS提供了Worker和TaskPool两种多线程并发能力,多线程并发允许在同一时间段内同时执行多段代码,这两个并发的基本能力可参见 TaskPool和Worker的对比 。

在介绍Worker和TaskPool的详细使用方法前,我们先简单介绍并发模型的相关概念,以便于大家的理解。

并发模型概述

并发的意思是多个任务同时执行。并发模型分为两大类:基于内存共享的并发模型和基于消息传递的并发模型。

在基于内存共享的并发模型中,并发线程通过读写内存中的共享对象来进行交互。基于共享内存的并发编程需要满足三条性质:

●原子性:指一个操作是不可中断的,要么全部执行成功要么全部执行失败。
●有序性:指程序执行的顺序必须符合预期,不能出现乱序的情况。
●可见性:指当一个线程修改了共享变量后,其他线程能够立即得知这个修改。

现代程序语言一般通过锁、内存屏障、原子指令来满足这三条性质。基于内存共享的并发模型与底层硬件接近,在能正确撰写并发代码的情况下,可以最大发挥底层硬件性能,实现性能优秀的多线程程序。但是这种并发模型难以掌握,即使资深的程序员也非常容易犯错。典型的基于内存共享并发模型的程序语言有C++ 、Swift和Java等。

在基于消息传递的并发模型中,并发线程的内存相互隔离,需要通过通信通道相互发送消息来进行交互。典型的基于消息传递的并发模型一般有两种:CSP和Actor。

CSP(Communicating Sequential Processes,通信顺序进程)中的计算单元并不能直接互相发送信息。需要通过通道(Channel)作为媒介进行消息传递:发送方需要将消息发送到Channel,而接收方需要从Channel读取消息。与CSP不同,在Actor模型中,每个Actor可以看做一个独立的计算单元,并且相互之间内存隔离,每个Actor中存在信箱(Mail Box),Actor之间可以直接进行消息传递,如下图所示:
图1 Actor消息传递示意图
在这里插入图片描述

CSP与Actor之间的主要区别:

●Actor需要明确指定消息接收方,而CSP中处理单元不用关心这些,只需要把消息发送给Channel,而接收方只需要从Channel读取消息。
●由于在默认情况下Channel是没有缓存的,因此对Channel的发送(Send)动作是同步阻塞的,直到另外一个持有该Channel引用的执行块取出消息,而Actor模型中信箱本质是队列,因此消息的发送和接收可以是异步的。

典型的基于消息传递的并发模型的程序语言有:Dart、JS和ArkTS。OpenHarmony中Worker和TaskPool都是基于Actor并发模型实现的并发能力。

Worker

基本概念和运作原理

OpenHarmony中的Worker是一个独立的线程,基本概念可参见 TaskPool和Worker的对比 。Worker拥有独立的运行环境,每个Worker线程和主线程一样拥有自己的内存空间、消息队列(MessageQueue)、事件轮询机制(EventLoop)、调用栈(CallStack)等。线程之间通过消息(Massage)进行交互,如下图所示:

图2 线程交互示意图
在这里插入图片描述

在多核的情况下(下图中的CPU 1和CPU 2同时工作),多个Worker线程(下图中的worker thread1和worker thread2)可以同时执行,因此Worker线程做到了真正的并发,如下图所示:

图3 Worker线程并发示意图
在这里插入图片描述

使用场景和开发示例

对于Worker,有以下适用场景:

●运行时间超过3分钟的任务,需要使用Worker。

●有关联的一系列同步任务,例如数据库增、删、改、查等,要保证同一个句柄,需要使用Worker。

以视频解压的场景为例,点击右上角下载按钮,该示例会执行网络下载并监听,下载完成后自动执行解压操作。当视频过大时,可能会出现解压时长超过3分钟耗时的情况,因此我们选用该场景来说明如何使用Worker。
场景预览图如下所示:

图4 场景预

### 鸿蒙系统南向接口中的队列使用与实现 鸿蒙系统的南向接口设计主要用于连接底层硬件设备和上层软件服务,其核心目标之一是提供高效的数据传输机制。在实际开发过程中,队列作为一种常见的数据结构,在南向接口的设计中扮演着重要角色。 #### 1. 队列的作用 在鸿蒙系统的南向接口中,队列通常用于处理异步事件或缓冲数据流。例如,在摄像头模块的实现中,框架层(PipelineCore)通过队列来管理来自不同硬件设备的数据流[^2]。这种设计可以有效缓解上下层之间速度不匹配的问题,提升整体性能。 #### 2. 实现方式 鸿蒙系统基于C/C++语言实现了多种类型的队列,具体实现依赖于具体的场景需求。以下是几种常见的方式: - **环形缓冲区(Circular Buffer)** 环形缓冲区是一种典型的固定大小队列实现方法,广泛应用于实时数据采集场景。它能够有效地利用内存资源并减少动态分配带来的开销。在鸿蒙的驱动子系统中,环形缓冲区常被用来存储传感器或其他外设产生的连续数据流[^3]。 - **链表队列(Linked List Queue)** 对于需要频繁插入删除操作的应用场合,则更适合采用链表形式构建队列。这种方式虽然可能增加一定的空间消耗,但在灵活性方面具有明显优势。特别是在多线程环境下,可以通过加锁机制保障访问安全性。 ```c // 示例代码:简单单向链表队列定义 typedef struct Node { void *data; struct Node *next; } Node; typedef struct { Node *head, *tail; int size; } LinkedListQueue; void enqueue(LinkedListQueue *queue, void *item); void* dequeue(LinkedListQueue *queue); ``` - **消息队列(Message Queue)** 消息队列作为操作系统层面的一种IPC工具,在跨进程通讯中有重要作用。对于某些复杂的分布式应用场景而言,可以直接调用OS提供的API完成相应功能而无需自行编写额外逻辑。然而需要注意的是,由于这类方案往往伴随着较高的延迟成本,因此仅适用于那些对响应时间要求相对宽松的任务类型。 #### 3. 应用实例 以Camera Host为例,当图像帧从ISP单元传递至主机侧时,会先进入到一个预置好的FIFO队列等待进一步处理。此时如果发现当前缓存已满,则触发丢弃策略或者暂停输入直到有足够的可用空间为止;反之亦然——一旦检测到空闲位置即刻允许新的元素加入其中[^2]。 另外,《OpenHarmony源码解析》提到过关于如何配置特定平台下的编译选项从而启用不同的队列算法优化路径等内容[^3],这表明开发者可以根据实际情况灵活调整最佳实践组合达到预期效果。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值