【问题标题】:Implementing a recursive lock实现递归锁
【发布时间】:2019-05-19 20:52:18
【问题描述】:

我创建了一个 Synchronizable mixin,它提供了synchronized 函数:

const lock = Symbol('Synchronizable lock');
const queue = Symbol('Synchronizable queue');

export class Synchronizable {
  private [lock] = false;
  private [queue]: Array<() => void> = [];

  public async synchronized<T>(fn: () => Promise<T>): Promise<T> {
    while (true) {
      if (this[lock]) await new Promise(resolve => this[queue].push(resolve));
      else {
        this[lock] = true;
        try {
          return await fn();
        } finally {
          this[lock] = false;
          const tmp = this[queue];
          this[queue] = [];
          tmp.forEach(e => e());
        }
      }
    }
  }
}

但是锁不是递归的,加锁时锁定对象会导致死锁:

const c = new Synchronizable();
await c.synchronized(() => c.synchronized(async () => void 0));

如何实现递归锁?

完整代码已上传至github,并附有测试用例

最初的想法

就像任何其他语言一样,在锁定时保存当前线程 ID,然后将保存的线程 ID 与当前线程 ID 进行比较,如果匹配则继续。

但是 javascript 不提供 thread-id,并且 defer 闭包不会生成新的 id。

第二个想法

跟踪调用堆栈,找到堆栈内的任何其他锁调用,检查是否是同一个锁。

问题是堆栈跟踪可能不会跟随回调,例如setTimeout,因此它无法在回调之前检测到锁。

【问题讨论】:

  • @Rajesh 你可以试试测试用例,它是绝对需要的。测试用例还演示了用例。
  • @ZangMingJie 为什么单线程环境需要锁?
  • @Dmitry 查看测试用例,这些测试用例也演示了用例。
  • @ZangMingJie,单线程环境不需要锁。来自维基百科,在计算机科学中,锁或互斥锁(来自互斥)是一种同步机制,用于在有许多执行线程的环境中强制限制对资源的访问。锁旨在强制执行互斥并发控制策略。
  • 那么你期望在递归的情况下会发生什么?例外?

标签: javascript typescript async-await


【解决方案1】:

我发现使用 Zone.js 可以使用第一种方法来实现,其中 Zone.js 提供了一种定义线程局部变量的方法。

【讨论】:

    猜你喜欢
    • 2010-11-24
    • 1970-01-01
    • 2010-09-16
    • 2019-04-07
    • 2014-04-15
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2016-11-12
    相关资源
    最近更新 更多