无锁多线程编程是否更容易?

时间:2009-09-06 11:40:29

标签: c multithreading lock-free

我只是读了一下这个主题,但似乎唯一的好处是绕过争用问题,但它不会对死锁问题产生任何重要影响,因为无锁的代码是如此之小和基本(fifos,lifos,hash),从来没有出现死锁问题。

所以关于性能 - 这是对的吗?

7 个答案:

答案 0 :(得分:9)

无锁编程(据我所知)总是关于性能,否则在大多数情况下使用锁更简单,因此更可取。

但请注意,使用无锁编程,您最终可能会遇到实时锁定的死锁,这对于诊断来说要困难得多,因为我所知道的任何工具都不是用来诊断它的(尽管我可能在那里错了)。

我会说,如果必须的话,只能沿着无锁的道路前进;也就是说,你有一个场景,你有一个严重争用的锁,这会损害你的表现。 (如果没有破坏,请不要修理它。)

答案 1 :(得分:9)

一些问题。

我们很快将面临64,128和256核心的桌面系统。该领域的并行性与我们目前的2,4,8核心经验不同;由于争用,在这种小型系统上成功运行的算法将在高度并行的系统上运行 slow

从这个意义上说,无锁​​是很重要的,因为它对解决可扩展性有很大帮助。

还有一些非常特定的区域,其中无锁是非常方便的,例如Windows内核,其中存在禁止任何类型的睡眠(例如等待)的执行模式,这显然是非常有限的。数据结构,但无锁提供了一个很好的解决方案。

此外,无锁数据结构通常没有故障模式;它们实际上不会失败,基于锁的数据结构当然无法获得锁定。不必担心失败会简化代码。

我已经编写了一个无锁数据结构库,我将尽快发布。我认为如果开发人员可以获得经过充分验证的API,那么他就可以使用它 - 无论是否无锁,都无关紧要,他不需要担心底层实现的复杂性 - 以及这是要走的路。

答案 2 :(得分:1)

这也是关于可扩展性的。为了获得性能提升,您必须将您正在处理的问题并行化,以便可以跨多个核心扩展它们 - 越多越好。

传统的方法是锁定需要并行访问的数据结构,但是你可以运行的线程越多,就越平行,这就成了瓶颈。

是的,这是关于表现......

答案 3 :(得分:1)

对于抢占式线程,在持有锁的情况下挂起的线程可以阻止线程,否则这些线程会向前推进。无锁是没有那个问题,因为Herlihy的定义,其他一些线程总是能够取得进展。

对于非抢占式线程,它并不重要,因为即使是基于自旋锁的解决方案也不受Herlihy定义的锁定。

答案 4 :(得分:1)

这是关于表演 - 但也涉及多线程负载的能力:

  • 授予对部分代码的独占访问权:当线程有锁时,其他线程正在旋转(在尝试获取锁时循环) )或阻塞,睡觉直到锁被释放(这通常发生在旋转持续太长时间);

  • atomic 操作通过使用不间断的内部CPU指令授予对资源的独占访问权(通常是字大小的变量或指针)。

当锁定其他线程的执行时,程序会变慢。 当原子操作连续执行(一个接一个)时,没有阻塞*。

(*)只要尝试访问同一资源的并发CPU 的数量不会产生瓶颈 - 但我们还没有足够的CPU内核将此视为问题。

我已经处理了这个问题,为我正在处理的服务器写了一个无等待(没有等待状态的无锁)Key-Value存储。

Tokyo Cabinet(甚至是TC-FIXED,一个简单的数组)这样的库依靠锁来保持数据库的完整性:

“当写线程正在操作数据库时,其他读取线程和写入线程被阻止”(Tokyo Cabinet文档)

没有并发性的测试结果(单线程测试):

SQLite   time: 56.4 ms (a B-tree)
TC       time: 10.7 ms (a hash table)
TC-FIXED time:  1.3 ms (an array)
G-WAN KV time:  0.4 ms (something new which works, but I am not sure a name is needed)

通过并发(在同一个数据库中写入和读取多个线程),只有G-WAN KV在同一测试中幸存下来,因为(与其他测试相比)它永远不会阻塞。

所以,是的,这个KV商店使开发人员更容易使用它,因为他们不必关心线程问题。然而,以这种方式工作并非易事。

答案 5 :(得分:0)

我相信我看到一篇文章在数学上证明了任何算法都可以以无等待的方式编写(这基本上意味着您可以确保每个线程始终朝着目标前进)。这意味着它可以应用于任何大规模应用程序(毕竟,程序只是一个具有许多参数的算法),并且因为等待自由确保其中不会发生死锁/活锁(只要它没有'它有防止它真正等待的错误),它确实简化了程序的那一面。另一方面,数学证明与实际实现代码本身相差甚远(AFAIK,甚至没有可以在PC上运行的完全无锁的链表,我见过覆盖大多数部分的链表,但是它们通常要么无法处理某些常用功能,要么某些功能需要锁定结构。

另外,我还发现了另一个证据,表明由于概率定律和其他各种因素,任何无锁算法实际上都可以被视为无等待。

答案 6 :(得分:0)

  1. 可扩展性是高效多/手动编程中非常重要的问题。最大的限制因素实际上是应该以串行方式执行的代码部分(参见Amdahl's Law)。但是,对锁的争论也很成问题。

  2. 无锁算法解决了传统锁具有的可扩展性问题。所以,我可以说无锁是主要用于性能,而不是降低死锁的可能性。

  3. 但是,请记住,使用当前的x86架构,编写一般无锁算法不可能。这是因为我们不能在当前x86中原子地交换任意大小的数据(对于除Sun的ROCK之外的其他架构也是如此)。因此,目前无锁数据结构非常有限,并且非常适合特定用途。

  4. 我认为目前无锁数据结构将在十年内不再使用。我强烈期望硬件辅助的一般无锁机制(是的,即事务内存,TM)将在十年内实现。如果实现任何类型的TM,虽然它不能完美地解决锁的问题,但是将消除许多问题(包括优先级倒置和死锁)。但是,在硬件中实现TM仍然非常具有挑战性,而在x86中,只提出了a draft

  5. 它仍然太长:2句话摘要。

    无锁数据结构不是基于锁的多线程编程的灵丹妙药(即使TM不是。如果你真的需要可扩展性并且在锁争用方面遇到麻烦,那么考虑无锁数据结构。