关于线程消毒剂的一些知识

自Xcode 8以来可用的线程清理器或TSan-LLVM是一种工具,当多个线程尝试以非原子方式访问同一内存区域并且其中至少一个线程执行一次写操作时,该工具可使我们调试数据竞争。 这种数据竞赛真的很难调试,因为它们极其不可预测,有时可以工作,有时不能,您永远都不知道首先到达那里的线程。

在本文中,我们将尝试更多地了解它可以做什么以及如何工作。

怎么运行的

让我们来看一个包含一段包含两个队列的数据争用的代码示例,并查看Thread Sanitizer如何帮助我们对其进行调试。

在上面的代码中,我们在两个不同的队列中写入相同的全局变量文本 ,然后,我们对该变量进行了读取。 但是阅读代码,您能回答将输出什么值? 哪个队列先写? 这是不可预测的,而且真的很难调试。

那就是Thread Sanitizer来帮助我们的地方。

首先,我们必须在Xcode中启用Thread Sanitizer:

在“产品”>“方案”>“编辑方案”上,在“运行”操作的“诊断”部分中,只需检查“线程清理器”

如果在命令行上运行,则可以为以下每个命令中的每个标志启用它:

  • clang -fsanitize =线程
  • swiftc -sanitize =线程
  • xcodebuild -enableThreadSanitizer是

您可以在Apple文档中找到有关启用Thread Sanitizer的信息。

重要

Apple Core Diagnostics文档中有两个非常重要的内容

Thread Sanitizer仅支持64位macOS和64位iOS和tvOS模拟器(不支持watchOS)。 在设备上运行应用程序时,无法使用它。

以及使用此工具对性能的影响

在启用了Thread Sanitizer检查的情况下运行代码可能导致CPU速度降低2%至20%,并使内存使用量增加5%至10%。 通过在-O1优化级别进行编译,可以提高内存利用率和CPU开销。

因此,既然我们已经启用了Thread Sanitizer,现在让我们运行我们之前编写的代码。

我们在运行时看到的第一件事是Thread Sanitizer发出的警告,告诉我们这里存在竞争条件,结果可能无法预测。

同样在Xcode侧栏的警告部分,您可以看到以下警告:

控制台上也有带有相同警告的输出。

在Thread Sanitizer完成所有工作以显示可以在哪里出现这种竞争状况之后,我们可以更轻松地对其进行修复。

引擎盖下

为了更好地理解它,让我们记住Swift编译器的流程

swift编译器采用您的Swift代码,对其进行解析以生成抽象语法树(AST),然后进行语义分析,其中编译器采用解析器生成的AST并进行类型检查的AST并检查是否存在语义问题那。 然后,Swift中级语言生成(SILGen)阶段将通过语义分析生成的AST转换为他们所谓的原始SIL,在对SIL进行了一些优化(例如通用专业化和ARC优化)之后,将该优化的SIL传递给IRGen以生成中间语言。要传递给LLVM的Representation(IR),以使其继续作业并生成目标文件。

好,让我们回到Thread Sanitizer。

您可能已经在启用“线程清除程序”部分中注意到它需要重新编译。 这是因为Thread Sanitizer是在编译时完成的,并作为LLVM编译器的传递来实现。

所有的编译器检测都在LLVM IR级别上完成[3]。

基本上,Thread Sanitizer会在LLVM IR级别插入代码,该代码记录有关每个内存访问的信息。 有了这些信息,当接收到每个内存访问的事件时,它就可以基于状态机算法报告潜在的竞争(您可以在[3]中更详细地了解)。

通过首先使用-emit-ir进行编译,有一种方法可以在快速代码上看到Thread Sanitizer生成的实际代码。

  • swiftc -emit-ir -sanitize =线程您的代码.swift

然后仍然发出IR,但未禁用Thread Sanitizer

  • swiftc -emit-ir your-code.swift

这样,您可以进行比较,并查看在使用Thread Sanitizer编译的版本中插入了什么。

您可以在ThreadSanitizer [3]的LLVM Compiler编译时工具竞赛检测中看到关于编译器工具和状态机算法的非常详细的信息。

结论

数据争用是在实际的多线程应用程序上调试时最困难的事情之一。 Thread Sanitizer是一个非常有用的工具,可以帮助我们在这项艰巨的任务上获得很多帮助。 尽管在性能方面需要权衡取舍,但确实很容易在需要时启用它,而在不需要时禁用。

这就是本文的全部,希望您喜欢🙂

如果我有问题或您有任何意见或疑问,请告诉我。 我很高兴收到您的反馈feedback

您可以在Twitter上@ LucianoPassos11找到我。

感谢您阅读🙂

参考文献

  1. 螺纹消毒剂| Apple开发人员文档。 https://developer.apple.com/documentation/code_diagnostics/thread_sanitizer
  2. 数据竞赛| Apple开发人员文档。 https://developer.apple.com/documentation/code_diagnostics/thread_sanitizer/data_races
  3. Serebryany,K.,Potapenko,A.,Iskhodzhanov,T.,VyukovDynamic,D .:使用LLVM编译器对ThreadSanitizer进行编译时检测的种族检测。 https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/data-race-test/ThreadSanitizerLLVM.pdf
  4. Swift-LLVM的孩子,http://yaunch.io/llvm-and-swift/
  5. Greg Heo在iOS Conf SG 2017上发表了《娱乐与利润的编译器消毒剂》。