鸿蒙-阻塞式文件锁

一、背景

最近在做鸿蒙版本的埋点SDK, 涉及到多线程同步问题。我们都知道多线程存在并发问题(多线程同步和互斥的问题)。今天我介绍一下我在鸿蒙项目中,使用ArkTS的API实现阻塞式的同步锁,来确保线程安全。

1.1 鸿蒙的并发基础设施

在进入正文之前,我先介绍一下鸿蒙系统的并发基础设施,大概分为如下三类:

并发名称 特点 应用场景
TaskPool 短时间任务 网络上传、文件写入(线程来源于线程池) 任务无法和固定的线程绑定
Worker 单开一个线程 可以做 一些长的、周期性任务(类似于Java中new Thread)
Native -- 使用C/C++ , 利用NAPI

需要注意的是TaskPool、Worker是鸿蒙ArkTs SDK提供的API,这两种线程(轻量级进程 ) 之间是内存隔离, 只能够通过 特定的API传递一些@Sendable的数据, 不能够通过 **变量(引用)**的方式直接访问。

1.2 鸿蒙文件管理

鸿蒙的ArkTS SDK中,提供了 文件管理的API, 其中关于 锁的API有:

并发名称 特点
lock(exclusive?: boolean): Promise 文件阻塞式施加共享锁或独占锁,使用Promise异步返回
lock(exclusive?: boolean, callback: AsyncCallback): void 文件阻塞式施加共享锁或独占锁,使Callback异步回调。
tryLock(exclusive?: boolean): void 文件非阻塞式施加共享锁或独占锁
unlock(): void 以同步方式给文件解锁。

上述的API,已经非常丰富了,几乎可以满足所有的开发需求。 但是我的情况比较特殊: 我期望的是我的线程通过tryLock去获取互斥锁,如果没有获取到就一直轮训

你可能会有疑问: lock(exclusive?: boolean): Promise + await 不正好能够满足需求吗? 是的, 如果确实可以,但是这在鸿蒙当中有一个前提:是需要调用代码块是异步的(方法被async修饰)。这一点我不期望的。

二、场景

如上图所示,线程一和线程二 同时 访问cache.lock的文件锁,获得锁之后,然后对journal文件操作,以确保journal文件内容的完整性和可靠性。

三、实现

同步代码通过轮训实现的同步锁:

typescript 复制代码
import fs from '@ohos.file.fs';
import { FILE_LOCK_TAG } from './FileLockTest';
import { process } from '@kit.ArkTS';

export class FileSyncLock {

  parentDirPath:string
  lockFilePath:string
  workId?:string
  ...

  // 尝试打开 this.lockFilePath文件并,进行加锁
  acquireLockSync():fs.File | undefined {
    let file:fs.File | undefined = undefined
    do {
      try {
        file = fs.openSync(this.lockFilePath,fs.OpenMode.CREATE);
        file.tryLock(true)
        console.error(FILE_LOCK_TAG,`${this.workId}  ${process.tid} Lock acquired. fd : ${file.fd}`);
      } catch (err) {
      }
    } while (!file)
    return file
  }

  // 解锁并关闭某个文件
  releaseLock(file:fs.File) {
    try {
      file.unlock()
      fs.closeSync(file);
      console.error(FILE_LOCK_TAG,`${this.workId} ${process.tid}  Lock released.`);
    } catch (err) {
      // console.debug(FILE_LOCK_TAG,`${this.workId}  ${process.tid}  Failed to release lock: ${JSON.stringify(err)}`);
    }
  }
}

调用方式:

typescript 复制代码
test() {
    let mLock:FileSyncLock = new FileSyncLock(data.cacheDir,"cache.lock",data.workId);
    let f:fs.File = mLock.acquireLockSync()
    // 做一些线程不安全的事情
    doSomethingUnsafe()
    mLock.releaseLock(f!!)
  }

四、写在最后

学到的内容

  1. fs.openSync(this.lockFilePath,fs.OpenMode.CREATE); 这个API只能确保是同步打开文件,获得一个句柄,不能自带加锁,需要额外调用Lock相关的API
  2. 上述的轮询时获得锁的方式是 不推荐的, 因为会使得当前线程一直处于活跃状态,对CPU不太友好,但是可以用于 临界资源竞争不太激烈的场景。
  3. 建议使用官网的 协程式获得锁 的方式, 更符合现代编程范式。

官网参考链接鸿蒙-文件管理
Github代码地址: : 阻塞式文件锁

相关推荐
雪芽蓝域zzs2 小时前
鸿蒙Next开发 获取APP缓存大小和清除缓存
缓存·华为·harmonyos
Robot2516 小时前
「华为」人形机器人赛道投资首秀!
大数据·人工智能·科技·microsoft·华为·机器人
鸿蒙布道师6 小时前
鸿蒙NEXT开发动画案例5
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
小诸葛的博客14 小时前
华为ensp实现跨vlan通信
网络·华为·智能路由器
康康这名还挺多15 小时前
鸿蒙HarmonyOS list优化一: list 结合 lazyforeach用法
数据结构·list·harmonyos·lazyforeach
晚秋大魔王19 小时前
OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——nettle库
linux·开源·harmonyos
python算法(魔法师版)1 天前
.NET 在鸿蒙系统上的适配现状
华为od·华为·华为云·.net·wpf·harmonyos
bestadc1 天前
鸿蒙 UIAbility组件与UI的数据同步和窗口关闭
harmonyos
枫叶丹41 天前
【HarmonyOS Next之旅】DevEco Studio使用指南(二十二)
华为·harmonyos·deveco studio·harmonyos next
ax一号街阿楠1 天前
华为FAT AP配置 真机
网络·华为·智能路由器