我创建了一个 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 不提供线程 ID,延迟闭包不会生成新的 ID。
再想一想
跟踪调用堆栈,在堆栈中找到任何其他锁调用,检查它是否是同一个锁。
问题是堆栈跟踪可能不会跟随回调,例如 setTimeout
,因此它无法在回调之前检测到锁。
最佳答案
我发现使用第一种方法可以通过 Zone.js 实现,其中 Zone.js 提供了一种定义线程局部变量的方法。
关于javascript - 实现递归锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53849947/