dic*_*oce 9 linux concurrency circular-buffer memory-barriers
有一篇文章在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);
Run Code Online (Sandbox Code Playgroud)
问题:
这是"消费者":
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);
Run Code Online (Sandbox Code Playgroud)
特定于"消费者"的问题:
对于制片人:
spin_lock()是为了防止两个生产者同时尝试修改队列.ACCESS_ONCE确实可以防止重新排序,它还可以防止编译器稍后重新加载该值.(有一篇关于ACCESS_ONCELWN 的文章进一步扩展了这一点)head值.消费者:
smp_read_barrier_depends()是一个数据依赖障碍,它是一种较弱的读取障碍形式(见2).在这种情况下的效果是确保buffer->tail在将其用作数组索引之前读取buffer[tail].smp_mb() 这是一个完整的内存屏障,确保在这一点上提交所有读写操作.其他参考:
(注意:我不完全确定我在制作人中的5和消费者的答案,但我相信他们是事实的近似.我强烈建议阅读有关内存障碍的文档页面,因为它更多比我在这里写的任何内容都要全面.)
| 归档时间: |
|
| 查看次数: |
11820 次 |
| 最近记录: |