无锁的多生产商单量消费者(MPSC)环形缓冲区,该戒指缓冲区支持连续范围操作,并且可以方便地用于消息传递。该实施是在C11中编写的,并根据2条规则BSD许可分发。
int ringbuf_setup(ringbuf_t *rbuf, unsigned nworkers, size_t length)
rbuf是指向不透明环缓冲物对象的指针。呼叫者负责为此对象分配空间。通常,如果使用线程或在共享内存中保留,则该对象将动态分配,如果使用进程。对象的分配大小应使用ringbuf_get_sizes函数获得。在成功时返回0,失败返回-1。 void ringbuf_get_sizes(unsigned nworkers, size_t *ringbuf_obj_size, size_t *ringbuf_worker_size)
ringbuf_t的大小,并选择为ringbuf_worker_t结构。 ringbuf_t结构的大小取决于nworkers参数指定的工人数量。 ringbuf_worker_t *ringbuf_register(ringbuf_t *rbuf, unsigned i)
i是一个工人号码,从零开始(即比设置中使用的nworkers )。成功时,将指针返回到不透明的ringbuf_worker_t结构化,这是ringbuf_t内存块的一部分。失败时,返回NULL 。 void ringbuf_unregister(ringbuf_t *rbuf, ringbuf_worker_t *worker)
ssize_t ringbuf_acquire(ringbuf_t *rbuf, ringbuf_worker_t *worker, size_t len)
ringbuf_produce函数以表明这一点。不允许嵌套收到的呼叫。 void ringbuf_produce(ringbuf_t *rbuf, ringbuf_worker_t *worker)
size_t ringbuf_consume(ringbuf_t *rbuf, size_t *offset)
ringbuf_release函数以表明这一点。 void ringbuf_release(ringbuf_t *rbuf, size_t nbytes)
消费者将返回产生的连续范围,即ringbuf_consume呼叫不会返回部分范围。如果您将产生的范围视为消息,那么消费者将返回一条消息,始终以消息边界结束。这种行为使我们可以将此环缓冲区实现用作消息队列。
在24核X86机器上对实现进行了广泛的测试,有关该技术的详细信息,请参见应力测试。它还提供了一个示例,如何将机制用于消息传递。
此环缓冲区实现总是为生产者提供连续的空间范围。如果所请求的范围最终无法拟合,则可以通过早期的包裹实现。这意味着如果请求的范围大于缓冲区大小的一半,则ringbuf_acquire调用可能会失败。因此,可能有必要确保环缓冲区的大小至少是最大生产单元尺寸的两倍。
还应注意的是,这种设计的权衡之一是,消费者目前在生产商列表中执行O(n)扫描。
生产者:
if (( w = ringbuf_register ( r , worker_id )) == NULL )
err ( EXIT_FAILURE , "ringbuf_register" )
...
if (( off = ringbuf_acquire ( r , w , len )) != -1 ) {
memcpy ( & buf [ off ], payload , len );
ringbuf_produce ( r , tls );
}消费者:
if (( len = ringbuf_consume ( r , & off )) != 0 ) {
process ( & buf [ off ], len );
ringbuf_release ( r , len );
}