第 13 章 lockfree相关

少锁的环形缓冲区设计 tail - 新的写操作在这里 head - 新的读操作在这里 producer - 写入缓冲区的任务,生产者,或写者 writer - 跟跟上面的producer一样 consumer - 读出内容的任务,消费者,或读者 reader - 跟上面的consumer一样 reader_page - 在缓冲区外被读者单独使用的页 head_page - 一个指针,指向读者下个使用的页 tail_page - 一个指针,指向下个将被写入的页 commit_page - 一个指针,指向最近完成没有写的页 cmpxchg - 硬件辅助原子事务执行如下: A = B 假设A == C R = cmpxchg (A, C, B) 是说我们使用B替换A,如果尽当前A等于C,我们将旧的当前的A 放进R,R得到之前A不管A是否被更新为B或没有。通过比较R == C来检查是否更新成功 通常环形缓冲区 通常被用在overwrite模式或在生产者/消费者模式。 生产者/消费者模式是生产者在消费者读取内容前填充缓冲区,否则停止写入缓冲区。它 将丢失最近的事件。 Overwrite模式是生产者在消费者读取内容前填充缓冲区,否则覆写旧的数据,它将丢失 最老的事件 没有两个写者能在同一个事件写入内容(在一个per-cpu buffer), 但是一个写者可能中断另外的写者,但是它必须完成写在之前写者可能继续之前。 这是非常重要的算法。写者像一个“栈”,中断工作的方式增强了这种行为。 writer1 start <preempted> writer2 start <preempted> writer3 start writer3 finishes writer2 finishes writer1 finishes 这个很像写者被中断打断,后中断也去做写操作。 读者可能发生在任何时候,但是没有两个读者可能同时运行,或者不能一个读者抢占/中断另外一个 读者。一个读者不能抢占/中断一个写者,但是它可能读/消费一个缓冲区,同时一个写者在写, 但那是读者必须在另外一个处理器上做这些。一个读者可能读它在它自己的处理器上,并能被写者 抢占。 一个写者能抢占一个读者,但是一个读者不能抢占一个写者。但是一个写者可以同时读缓冲区在 另外处理器上。 环形缓冲区由一个链表绑在一起的一系列页组成。 在初始化时,一个reader_page被申请给读者,它不是环形缓冲区的一部分 head_page, tail_page和commit_page将被初始化指向同一个页。 reader_page被初始化,有它next指针指向head_page,它的prev指针指向在head_page之前的页 reader有它自己的页来使用,在开始时,这个页被申请,但是没有关联到链表。当reader想要读 缓冲区时,如果它的页是空的,它将置换它的页和head_page,旧的reader page将变成环形缓冲区的 一部分,并且也head_page将被移除。插入的旧read page就变为新的head_page. 一旦新的页给reader,它将做任何它想做的,只要写者离开了这个页。