2

在这里,我看到了 JavaScript 死锁和这段代码:

var loop = true,
block = setTimeout(function(){loop = false}, 1);
while(loop);

这绝对是无限循环并导致浏览器冻结。据说deadlock is created when one operation wait another one to be executed and vice-versa
我的问题是,除此之外,什么样的情况会发生死锁以及避免它们的方法?

4

2 回答 2

9

Javascript可以死锁,并行执行不是死锁的必要条件。javascript VM 是单线程的,但它具有并发执行范例,因此可以满足 Coffman 条件:

这是一个例子:

function makeFuture() {
  let resolve;
  let reject;
  let promise = new Promise((d, e) => {
    resolve = d;
    reject = e;
  });
  return [promise, resolve, reject];
}

class Lock {
  constructor() {
    this.q = [];
    this.running = false;
  }
  async runQueue() {
    if (this.running) return;
    this.running = true;
    while (this.q.length > 0) {
      const { asyncFunction, resolve, reject } = this.q.shift();
      try {
        let result = await asyncFunction();
        resolve(await asyncFunction());
      } catch (error) {
        reject(error);
      }
    }
    this.running = false;
  }
  runTask(asyncFunction) {
    const [promise, resolve, reject] = makeFuture();
    this.q.push({ asyncFunction, resolve, reject });
    this.runQueue();
    return promise;
  }
}

const dbLock = new Lock();

let taskResultPromise = dbLock.runTask(async () => {
  console.log('about to deadlock');
  let value = await dbLock.runTask(async () => { return 'value'; });
  value //?
  console.log('did not deadlock');
  return value;
});

来自维基百科的死锁的科夫曼条件是:

  1. 互斥 - Lock 类确保对数据库资源的独占并发访问。资源是(数据库锁,'值'值)
  2. 持有并等待 - 任务 1 持有数据库锁并等待来自任务 2 的“值”。任务 2 持有“值”并等待数据库锁
  3. 无抢占 - javascript JVM 没有强制任一任务抢先释放其锁定的机制。
  4. 循环等待 - 见 (2)。
于 2020-08-05T18:41:46.160 回答
8

这不是死锁,只是一个无限循环,你不能在 JavaScript 中出现死锁,因为你不能有多个线程访问你的数据。

这里发生的是,由于你的循环永远不会结束并且 js 引擎是单线程的(关于你的脚本),调度程序永远不会调用你给setTimeout. 事实上,如果没有第二行,你会有完全相同的行为。

于 2013-05-13T20:03:42.583 回答