← 中文资源

简体中文版本

异步读写锁

用公平的基于 promise 的读写锁协调并发的异步读者与独占写者。

阅读英文原文

功能说明

该示例让多个异步读者共享访问、写者独占访问成为可能。acquireRead 在无写者且无排队时立即放行,否则排队;acquireWrite 需等待所有读者离开且无写者。释放后由 drain 按队列顺序唤醒,队列里若队首是写者则必须等读者清零,从而避免写者饿死。

关键代码

请求先判断能否立即满足:无排队、无写者,且读者请求只要求当前无写者,写者请求要求读者为零。满足则直接解析并立即返回(由调用方随后自增计数),否则入队等待。drain 只处理队首:写者需读者与写者均为空,读者只需无写者。以队首判断而非扫描整队,保证近似先进先出的公平性。release 更新状态后统一调用 drain。

使用注意

读写锁适合读远多于写的状态;写频繁时其簿记开销可能超过收益,普通互斥更简单。绝不要尝试把读锁就地升级为写锁,本实现不支持,会死锁;应先释放再以写模式重新获取,并重新校验数据。等待者按队首推进,但读者释放后可能连续放行多个读者,这符合设计;若需严格写者优先,应在排队时加入额外策略。

代码示例

export class AsyncReaderWriterLock {
  private readers = 0;
  private writer = false;
  private queue: Array<{ write: boolean; resolve: () => void }> = [];

  async acquireRead(): Promise<() => void> {
    await this.request(false);
    this.readers += 1;
    return () => this.release(false);
  }

  async acquireWrite(): Promise<() => void> {
    await this.request(true);
    this.writer = true;
    return () => this.release(true);
  }

  private request(write: boolean): Promise<void> {
    if (this.queue.length === 0 && !this.writer && (write || this.readers >= 0)) {
      if (write ? this.readers === 0 : !this.writer) return Promise.resolve();
    }
    return new Promise((resolve) => this.queue.push({ write, resolve }));
  }

  private release(write: boolean) {
    if (write) this.writer = false;
    else this.readers -= 1;
    this.drain();
  }

  private drain() {
    while (this.queue.length > 0) {
      const next = this.queue[0] as { write: boolean; resolve: () => void };
      if (next.write) {
        if (this.writer || this.readers > 0) return;
        (this.queue.shift() as { resolve: () => void }).resolve();
        return;
      }
      (this.queue.shift() as { resolve: () => void }).resolve();
    }
  }
}