연속 범위 작업을 지원하고 메시지 전달에 편리하게 사용할 수있는 잠금 장치 다중 프로듀서 단일 소비자 (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 0부터 시작하는 작업자 번호입니다 (즉, 설정에 사용 된 nworkers 보다). 성공시 ringbuf_t 메모리 블록의 일부인 불투명 ringbuf_worker_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 );
}