Реализация рекурсивной блокировки - PullRequest
0 голосов
/ 19 декабря 2018

Я создал синхронизируемый миксин, который обеспечивает функцию 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 с тестовыми примерами

Первая мысль

Как и на любом другом языке, сохранитетекущий идентификатор потока при блокировке, затем сравните сохраненный идентификатор потока с текущим идентификатором потока, если сопоставление продолжается.

Но javascript не предоставляет идентификатор потока и откладывает закрытие не генерирует новый идентификатор.

Вторая мысль

отслеживать стек вызовов, находить любые другие вызовы блокировки внутри стека, проверять, является ли это такой же блокировкой.

Проблема в том, что трассировка стека может невыполните обратный вызов, например setTimeout, поэтому он не сможет обнаружить блокировку до обратного вызова.

1 Ответ

0 голосов
/ 23 декабря 2018

Я обнаружил, что этого можно добиться с помощью Zone.js, используя первый подход, где Zone.js предоставляет способ определения локальной переменной потока.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...