จาวาสคริปต์ - การใช้งานล็อกแบบเรียกซ้ำ
ฉันได้สร้างมิกซินที่สามารถซิงโครไนซ์ได้ ซึ่งให้ฟังก์ชัน 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 พร้อมกับชุดทดสอบ
ความคิดแรก
เหมือนกับภาษาอื่น ๆ ทุกภาษา บันทึก thread-id ปัจจุบันเมื่อทำการล็อก แล้วเปรียบเทียบ thread-id ที่บันทึกกับ thread-id ปัจจุบัน หากตรงกันก็ดำเนินการต่อ
แต่จาวาสคริปต์ไม่ได้ให้รหัสเธรด และการเลื่อนการปิดทับก็ไม่ได้สร้างรหัสใหม่
ความคิดที่สอง
ติดตามสแตกของการเรียก ใช้หาการเรียกล็อกอื่นใดภายในสแตก ตรวจสอบว่ามันเป็นล็อกเดียวกันหรือไม่
ปัญหาคือ stack trace อาจจะไม่ตาม callback เช่น setTimeout ดังนั้นมันจะไม่สามารถตรวจจับการล็อกก่อน callback ได้
คำตอบ #1
ฉันพบว่ามันสามารถทำได้โดยใช้ Zone.js ตามวิธีแรก ซึ่ง Zone.js ให้วิธีในการกำหนดตัวแปรเฉพาะเธรด