Language agnostic 如何构建无锁队列?

Language agnostic 如何构建无锁队列?,language-agnostic,queue,atomic,lockless,Language Agnostic,Queue,Atomic,Lockless,我花了今天的时间来调查没有上锁的队伍。我有一个多生产者,多消费者的情况。为了进行测试,我在Win32下实现了一个使用互锁SList的系统,它使我的基于任务的高线程代码的性能提高了一倍。但不幸的是,我希望支持多个平台。在多个平台上联锁本身不是问题,我可以安全地假设我可以无问题联锁。然而,实际的实现让我不知所措 最大的问题似乎是,您需要保证列表推送/弹出只使用一个联锁调用。否则你会留下空间让另一根线夹进去,把事情搞砸。我不确定微软的实现是如何运作的,我很想知道更多 有人能告诉我有用的信息吗(平台和语

我花了今天的时间来调查没有上锁的队伍。我有一个多生产者,多消费者的情况。为了进行测试,我在Win32下实现了一个使用互锁SList的系统,它使我的基于任务的高线程代码的性能提高了一倍。但不幸的是,我希望支持多个平台。在多个平台上联锁本身不是问题,我可以安全地假设我可以无问题联锁。然而,实际的实现让我不知所措

最大的问题似乎是,您需要保证列表推送/弹出只使用一个联锁调用。否则你会留下空间让另一根线夹进去,把事情搞砸。我不确定微软的实现是如何运作的,我很想知道更多

有人能告诉我有用的信息吗(平台和语言是非常不相关的)

除此之外,我想知道是否有可能实现一个无锁向量。这对我有很大的用处:) 干杯

编辑:读了herb的DDJ文章后,我可以看到一个简化的锁队列,它与我已经拥有的锁队列非常相似。然而,我注意到,最后有一些文件可以使用双重比较和交换(DCAS)操作实现真正的无锁排队。是否有人使用cmpxchg8b(或cmpxchg16b)实现了队列


我只是在考虑这一点(没有读过论文),但是你可以使用这个系统同时更新头和尾指针,从而避免在两个原子操作之间另一个线程跳转的问题。但是,您仍然需要获取下一个头部指针,以对照尾部指针进行测试,以查看您是否刚刚修改了尾部。当另一个线程准备自己更改此信息时,如何避免另一个线程更改此信息?这究竟是如何以无锁方式实现的?还是我最好读一读研究论文的不可破译性?;)

大家都有,也许你可以在那里找到一些灵感。其他有趣的文件是yqueue.hpp和atomic_ptr.hpp

我认为在这个主题上有一些有趣的讨论,特别是

您可能可以以最小的难度实现有限大小的队列。。。我最近在考虑这个问题,并提出了这个设计,但你可能会发现许多其他有趣的想法:(警告:它可能有一些问题!)

  • 队列是指向项的指针数组
  • 您必须管理2个指针(头、尾),它们以与循环缓冲区相同的方式在队列上工作
  • 如果
    head
    ==
    tail
    ,则没有项目
  • 如果您想要排队(ptr),则使用NULL(
    prev\u tail
    是交换的值)联锁交换
    tail
    • 如果
      prev\u tail==NULL
      ,请重试
    • 如果
      prev_tail+1
      (带环绕)==
      head
      ,则您的队列已满
    • 否则,将您的
      ptr
      放入
      *prev_tail
      并将
      prev_tail+1
      分配给
      tail
      (注意缓冲区环绕)
  • 对于
    dequeue()
    复制tmp\u head=head并选中
    tmp\u head=tail
    • 如果为true,则返回,因为队列为空
    • 如果是假的
      • 将tmp头保存为ptr
      • 进行CAS:比较
        head
        tmp\u head
        swap
        head
        head+1
      • 如果CAS失败--重新启动整个功能
      • 如果成功--返回
        ptr
您可以同时等待头部和尾部CAS操作,但是如果队列没有被竞争,您应该第一次成功,而不需要不必要的锁


无限大小的队列“有点”难;)但是您应该能够创建一个足够大的队列来满足大多数需求。

viraptor解决方案正在锁定,我知道没有多生产者/多消费者无锁队列算法

您可能想看看Herb Sutters低锁队列的实现


它确实使用了c++0x原子,但它(应该)很容易用您的特定体系结构实现原子操作(“使用GNU的同步”,solaris上的原子操作等等)。

请看,可惜您没有回答:)我没有找到该队列,而且,我没有找到Herb Sutter的多生产者/消费者DDJ文章:)谢谢!在没有锁的情况下,如何检查出列时的
head==tail
。您必须循环到开头,而不是围绕CAS本身。CAS将检测头部是否移动。听起来不错,我同意扩展的解释。只是检查:)。本质上,您所描述的是队列上的自旋锁,不是吗?为什么不使用基于旋转锁的临界截面?演出也会一样的,不是吗?至于说如果队列没有竞争,一切都会好起来。。。如果没有竞争,那么您也可以使用关键部分;)几乎-使用spinlock时,您实际上必须在不同的位置锁定,这使得整个操作需要更长的时间。我不知道有什么好处,但是如果你非常关心寻找一个无锁的解决方案,那么很难得到比一个赋值+一个CA更快的版本。我认为它是无锁的-它不包含互斥锁。它确实需要同步,但任何线程安全的东西都需要同步。如果不重试(操作本身,或重试互斥锁),则无法实现任何线程安全。很抱歉,我没有仔细检查您的解决方案是典型的单一生产者/消费者Cas队列,我以为它是一个自旋锁。然而,对于多个消费者和多个生产者来说,还没有关于CAS解决方案的科学论文,它们都失败了。“我们仍然在写自旋锁;我们只是手工写。这意味着这不是一个纯粹的问题。”