11

有一篇文章在:http ://lwn.net/Articles/378262/描述了 Linux 内核循环缓冲区的实现。我有一些问题:

这里是“生产者”:

spin_lock(&producer_lock);

unsigned long head = buffer->head;
unsigned long tail = ACCESS_ONCE(buffer->tail);

if (CIRC_SPACE(head, tail, buffer->size) >= 1) {
    /* insert one item into the buffer */
    struct item *item = buffer[head];

    produce_item(item);

    smp_wmb(); /* commit the item before incrementing the head */

    buffer->head = (head + 1) & (buffer->size - 1);

    /* wake_up() will make sure that the head is committed before
     * waking anyone up */
    wake_up(consumer);
}

spin_unlock(&producer_lock);

问题:

  1. 既然这段代码明确地处理了内存排序和原子性,那么 spin_lock() 的意义何在?
  2. 到目前为止,我的理解是 ACCESS_ONCE 停止编译器重新排序,对吗?
  3. producer_item(item) 是否简单地发出与该项目相关的所有写入?
  4. 我相信 smp_wmb() 保证produce_item(item) 中的所有写入都在随后的“发布”写入之前完成。真的?
  5. 我获得此代码的页面上的评论似乎暗示在更新头索引后通常需要 smp_wmb() ,但 wake_up(consumer) 会这样做,因此没有必要。真的吗?如果是,为什么?

这里是“消费者”:

spin_lock(&consumer_lock);

unsigned long head = ACCESS_ONCE(buffer->head);
unsigned long tail = buffer->tail;

if (CIRC_CNT(head, tail, buffer->size) >= 1) {
    /* read index before reading contents at that index */
    smp_read_barrier_depends();

    /* extract one item from the buffer */
    struct item *item = buffer[tail];

    consume_item(item);

    smp_mb(); /* finish reading descriptor before incrementing tail */

    buffer->tail = (tail + 1) & (buffer->size - 1);
}

spin_unlock(&consumer_lock);

特定于“消费者”的问题:

  1. smp_read_barrier_depends() 有什么作用?从论坛中的一些评论来看,您似乎可以在此处发布 smp_rmb(),但在某些架构上,这是不必要的(x86)且过于昂贵,因此创建了 smp_read_barrier_depends() 来选择性地执行此操作......也就是说,我真的不明白为什么 smp_rmb() 是必要的!
  2. smp_mb() 是否可以保证它之前的所有读取在它之后的写入之前完成?
4

1 回答 1

8

对于生产者:

  1. 这里spin_lock()是为了防止两个生产者同时尝试修改队列。
  2. ACCESS_ONCE确实可以防止重新排序,它还可以防止编译器稍后重新加载该值。(有一篇关于ACCESS_ONCELWN的文章对此进行了进一步扩展)
  3. 正确的。
  4. 也正确。
  5. 在唤醒消费者之前需要这里的(隐含的)写屏障,否则消费者可能看不到更新的head值。

消费者:

  1. smp_read_barrier_depends()是数据依赖屏障,它是读取屏障的较弱形式(参见2)。这种情况下的效果是确保buffer->tail在将其用作 中的数组索引之前读取它buffer[tail]
  2. smp_mb()这是一个完整的内存屏障,确保此时提交所有读取和写入。

附加参考:

(注意:我不完全确定我对生产者 5 和消费者 1 的答案,但我相信它们是事实的近似值。我强烈建议阅读有关内存障碍的文档页面,因为它更多比我在这里写的任何东西都全面。)

于 2013-01-17T17:39:37.220 回答