实施递归锁

时间:2018-12-19 11:05:55

标签: javascript typescript async-await

我创建了一个可同步的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不提供线程ID,并且延迟关闭操作不会生成新ID。

第二个想法

跟踪调用堆栈,找到堆栈中的其他任何锁调用,检查是否为相同的锁。

问题在于堆栈跟踪可能不会像setTimeout那样跟随回调,因此它将无法在回调之前检测到锁定。

1 个答案:

答案 0 :(得分:-1)

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