HarmonyOS中实现 非可重入锁 NonReentrantLock

背景

在多线程编程中,确保资源的互斥访问是至关重要的。允许并行执行,但需要同步机制来避免数据竞争和竞态条件。

锁的重要性

锁是一种同步机制,用于控制对共享资源的访问。在ArkTs中,传统的锁实现依赖于语言级别的原子操作,但随着共享内存的引入,我们需要一种新的同步机制。

使用SharedArrayBuffer和Atomics

SharedArrayBuffer允许在多个线程间共享内存,而Atomics提供了一组操作,用于在不同线程间进行线程安全的操作。

NonReentrantLock类实现

以下是NonReentrantLock类的实现,它使用SharedArrayBufferAtomics来确保互斥访问。

锁状态常量

const UNLOCKED = 0; // 锁未被任何线程占用
const LOCKED_SINGLE = 1; // 锁被单个线程占用
const LOCKED_MULTI = 2; // 锁被多个线程占用

NonReentrantLock类

export class NonReentrantLock {
  private flag: Int32Array;

  constructor(sab: SharedArrayBuffer) {
    this.flag = new Int32Array(sab);
  }

  public lock(): void {
    let c = UNLOCKED;
    while (Atomics.compareExchange(this.flag, 0, c, LOCKED_SINGLE) !== UNLOCKED) {
      if (c === LOCKED_MULTI || Atomics.compareExchange(this.flag, 0, LOCKED_SINGLE, LOCKED_MULTI) !== UNLOCKED) {
        Atomics.wait(this.flag, 0, LOCKED_MULTI);
      }
    }
  }

  public tryLock(): boolean {
    return Atomics.compareExchange(this.flag, 0, UNLOCKED, LOCKED_SINGLE) === UNLOCKED;
  }

  public unlock(): void {
    let v0 = Atomics.sub(this.flag, 0, 1);
    if (v0 !== LOCKED_SINGLE) {
      Atomics.store(this.flag, 0, UNLOCKED);
      Atomics.notify(this.flag, 0, 1);
    }
  }
}

使用示例

let sab = new SharedArrayBuffer(4);
let lock = new NonReentrantLock(sab);

// 某个线程尝试获取锁
lock.lock();

// 执行临界区代码...

// 释放锁
lock.unlock();

锁的获取与释放

  • lock方法用于获取锁,如果锁已被占用,调用线程将等待。
  • tryLock方法尝试获取锁,如果成功返回true,否则立即返回false
  • unlock方法用于释放锁,如果锁是被单个线程占用的,减少锁状态;如果是多线程占用的,设置为UNLOCKED并唤醒等待的线程。

注意事项

  • 使用SharedArrayBufferAtomics时,必须确保遵守同源策略。
  • 错误地使用这些API可能导致数据不一致和竞态条件。

结论

NonReentrantLock类提供了一种在ArkTs中实现线程安全锁的方法,这对于需要同步共享内存访问的多线程应用程序非常有用。

posted @ 2024-04-25 22:50  西北野狼  阅读(135)  评论(0编辑  收藏  举报