同步和异步如何与线程安全一起工作?

时间:2017-09-19 13:12:59

标签: swift asynchronous synchronization deadlock dispatch-queue

在Swift中,我们可以利用DispatchQueue来防止竞争状况。通过使用串行队列,所有内容都按顺序执行,从https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

开始
  

串行队列(也称为私有调度队列)执行一项任务   按照它们添加到队列的顺序。该   当前执行的任务在不同的线程上运行(可能会有所不同)   从任务到任务)由调度队列管理。串行   队列通常用于同步对特定资源的访问。

但我们可以通过在sync内执行async轻松创建死锁How do I create a deadlock in Grand Central Dispatch?

let serialQueue = DispatchQueue(label: "Cache.Storage.SerialQueue")
serialQueue.async {
  serialQueue.sync {
    print("perform some job")
  }

  print("this can't be reached")
}

防止死锁的唯一方法是使用2个串行队列,每个队列用于syncasync个功能版本。但是,当writeSyncwriteAsync同时发生时,这可能会导致罕见的情况。

我在fs module中看到它支持syncasync功能,例如fs.writeFileSync(file, data[, options])fs.writeFile(file, data[, options], callback)。通过允许这两个版本,这意味着用户可以按照他们想要的任何顺序使用它们吗?那么他们可以轻松地创建像我们上面所做的那样的死锁?

所以也许fs有一种聪明的方式可以应用于Swift?我们如何以线程安全的方式支持syncasync

1 个答案:

答案 0 :(得分:1)

serialQueue.async {
    serialQueue.sync {
        print("perform some job")
    }
}

此死锁是因为此代码在同一个调度队列上排队第二个任务,然后等待第二个任务完成。然而,第二个任务甚至无法启动,因为它是一个串行队列,并且第一个任务仍在执行(虽然在内部sempahore上被阻止)。

避免这种僵局的方法是从不这样做。当你认为你可以通过以下方式达到同样的效果时,这是特别愚蠢的:

serialQueue.async {
    print("perform some job")
}

有一些用例可以将不同队列中的同步任务运行到您所在的队列中。

  • 如果其他队列是主队列,并且您希望在继续执行
  • 之前在UI中执行某些操作
  • 作为不同队列中任务之间的同步方式,例如,如果要在执行之前确保另一个队列中的所有当前任务都已完成。

但是,在同一个队列中同步执行某些操作永远不会有理由,您可能只需执行某些操作。换句话说,如果您只是一个接一个地编写语句,它们已经在同一队列上同步执行。

  

我在fs模块中看到它支持同步和异步功能,如fs.writeFileSync(文件,数据[,选项])和fs.writeFile(文件,数据[,选项],回调)。通过允许这两个版本,这意味着用户可以按照他们想要的任何顺序使用它们吗?那么他们可以轻松地创建像我们上面所做的那样的死锁?

这取决于两个API的实现方式。调用的同步版本可能只是在不弄乱其他线程的情况下进行调用。如果它确实抓住了另一个线程然后等待其他线程完成,那么如果node.js服务器的线程用尽,则可能会出现死锁。