在我的多线程应用程序中,我发现有很严重的锁争用问题,这阻碍了在多个核心上实现良好的可扩展性。我决定使用无锁编程来解决这个问题。
我该如何编写一个无锁结构?
在我的多线程应用程序中,我发现有很严重的锁争用问题,这阻碍了在多个核心上实现良好的可扩展性。我决定使用无锁编程来解决这个问题。
我该如何编写一个无锁结构?
简短的回答是:
您无法创建无锁数据结构。
长的回答是:
如果您正在问这个问题,您可能还不了解足够的知识来创建一个无锁数据结构。创建无锁数据结构非常困难,只有这个领域中的专家才能做到。与其编写自己的结构,不如搜索现有的实现。当您找到它时,请检查它的广泛使用程度、文档是否完善、是否经过充分验证以及存在哪些限制 - 即使其他人发表的一些无锁数据结构也存在缺陷。
如果您没有找到相应于当前正在使用的结构的无锁结构,则改进算法,以便可以使用某个现有的结构。
如果您仍然坚持创建自己的无锁数据结构,请确保:
了解更多:
使用像Intel Threading Building Blocks这样的库,它包含了相当多的无锁结构和算法。我真的不建议您尝试编写自己的无锁代码,这非常容易出错且难以正确实现。
正如我的教授(来自《多处理器编程艺术》的Nir Shavit)告诉班上的同学们:请不要这样做。主要原因在于可测试性-您无法测试同步代码。您可以运行模拟,甚至可以进行压力测试。但这只是最好的粗略估计。您真正需要的是数学正确性证明。能够理解它们的人很少,更不用说写它们了。
因此,正如其他人所说:使用现有库。Joe Duffy的博客概述了一些技术(第28节)。您应该尝试的第一个技术是树分裂-将其分解为较小的任务并结合起来。
关于Suma的回答,在《多处理器编程艺术》一书中,Maurice Herlithy展示了实际上所有都可以不使用锁来实现(见第6章)。如果我没记错,这主要涉及将任务拆分为处理节点元素(类似于函数闭包),并将每个节点入队。线程将通过跟踪从最新缓存的节点开始的所有节点来计算状态。显然,这可能在最坏情况下导致顺序性能,但它具有重要的无锁特性,可以防止线程在持有锁时长时间被调度出去的情况。Herlithy还实现了理论上的无等待性能,这意味着一个线程不会永远等待赢得原子入队(这是很复杂的代码)。
一个多线程队列/栈是出奇的困难(请检查 ABA问题)。其他事情可能非常简单。熟悉 while(true) { atomicCAS直到我交换了它 } 块;它们非常强大。对于CAS正确性的直觉可以帮助开发,尽管您应该使用良好的测试和更强大的工具(也许 SKETCH,即将推出的MIT Kendo或spin?)来检查正确性,如果您可以将其简化为一个简单的结构。Cliff Click利用有限状态机进行了无锁数据结构的重大研究,并在Java中发布了许多实现。您可以在他的博客上找到他的论文、幻灯片和实现:http://blogs.azulsystems.com/cliff/
使用现有的实现,因为这个领域需要领域专家和博士(如果您想要正确完成!)
例如,在这里有一个代码库: