Tampon annulaire monocysumer (MPSC) sans producteur sans serrure qui prend en charge les opérations de plage contigu et qui peuvent être utilisées facilement pour le passage des messages. La mise en œuvre est écrite en C11 et distribuée en vertu de la licence BSD à 2 clauses.
int ringbuf_setup(ringbuf_t *rbuf, unsigned nworkers, size_t length)
rbuf est un pointeur vers l'objet de tampon annulaire opaque; L'appelant est responsable d'allouer l'espace pour cet objet. En règle générale, l'objet serait alloué dynamiquement si vous utilisez des threads ou réservés dans une mémoire partagée bloquée si vous utilisez des processus. La taille d'allocation de l'objet doit être obtenue à l'aide de la fonction ringbuf_get_sizes . Renvoie 0 sur le succès et -1 en échec. void ringbuf_get_sizes(unsigned nworkers, size_t *ringbuf_obj_size, size_t *ringbuf_worker_size)
ringbuf_t et, éventuellement, ringbuf_worker_t . La taille de la structure ringbuf_t dépend du nombre de travailleurs, spécifiés par le paramètre nworkers . ringbuf_worker_t *ringbuf_register(ringbuf_t *rbuf, unsigned i)
i est un numéro de travailleur, à partir de zéro (c'est-à-dire que nworkers utilisés dans la configuration). Au cours du succès, renvoie un pointeur vers un ringbuf_worker_t Structuré opaque, qui fait partie du bloc de mémoire ringbuf_t . En cas de défaillance, renvoie 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 doit être appelée pour l'indiquer. Les appels acquériaux imbriqués ne sont pas autorisés. void ringbuf_produce(ringbuf_t *rbuf, ringbuf_worker_t *worker)
size_t ringbuf_consume(ringbuf_t *rbuf, size_t *offset)
ringbuf_release doit être appelée pour l'indiquer. void ringbuf_release(ringbuf_t *rbuf, size_t nbytes)
Le consommateur renverra un bloc contigu de gammes produites, c'est-à-dire que l'appel ringbuf_consume ne renverra pas de gammes partielles. Si vous considérez la gamme produite comme un message, le consommateur renvoie un bloc de messages, se terminant toujours à la limite du message. Un tel comportement nous permet d'utiliser cette implémentation de tampon d'anneau comme file d'attente de messages.
La mise en œuvre a été largement testée sur une machine x86 à 24 cœurs, voir le test de contrainte pour les détails de la technique. Il fournit également un exemple comment le mécanisme peut être utilisé pour passer des messages.
Cette implémentation de tampon d'anneau fournit toujours une gamme d'espace contigu au producteur. Il est réalisé par une enveloppe précoce si la plage demandée ne peut pas s'adapter à la fin. L'implication de ceci est que l'appel ringbuf_acquire peut échouer si la plage demandée est supérieure à la moitié de la taille du tampon. Par conséquent, il peut être nécessaire de s'assurer que la taille du tampon d'anneau est au moins deux fois plus grande que la taille maximale de l'unité de production.
Il convient également de noter que l'un des compromis d'une telle conception est que le consommateur effectue actuellement une analyse O (n) sur la liste des producteurs.
Producteurs:
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 );
}Consommateur:
if (( len = ringbuf_consume ( r , & off )) != 0 ) {
process ( & buf [ off ], len );
ringbuf_release ( r , len );
}