Implementing a recursive lock

Viewed 210

I have created a Synchronizable mixin, which provides synchronized function:

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());
        }
      }
    }
  }
}

But the lock is not recursive, locking the object when locked will cause dead lock:

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

How to implement recursive lock ?

The full code is upload to github with testcases

First thought

Just like any other language, save current thread-id when lock then compare the saved thread-id with current thread-id, if match proceed.

But javascript doesn't provide thread-id, and defer a closure doesn't generate a new id.

Second thought

track the call stack, find any other lock call inside stack, check if it is the same lock.

The problem is that stack trace may not follow callback, like setTimeout, so it won't be able to detect a lock before the callback.

1 Answers

I found it is possible to achieve with Zone.js using first approach, where Zone.js provides a way to define thread-local variable.

Related