2017-02-15 7 views
2

je les conditions suivantes pour un mécanisme IPC sur Linux:Diffusion IPC sur Linux

  1. Il y a un seul processus de production, mais plusieurs processus de consommation. Les processus de consommation ne sont pas des enfants du processus de production. Ils sont élevés de façon indépendante.

  2. Les messages transportés sont des structures POD de taille fixe.

  3. Nous avons besoin d'utiliser une quantité de mémoire fixe pour ce mécanisme. Un mécanisme de type anneau tampon semble idéal ici.

  4. Le producteur doit courir très vite et ne jamais attendre les consommateurs. Au lieu de cela, il doit remplacer les entrées dans le tampon de taille fixe (pour IPC) et les consommateurs doivent détecter ce problème et simplement rattraper le producteur en sautant les messages intermédiaires dans le cas d'un enroulement autour.

  5. Les consommateurs peuvent monter et descendre à tout moment et il ne devrait y avoir aucune poignée de main explicite entre le producteur unique et les consommateurs éphémères au fur et à mesure qu'ils montent et sortent. Donc, quand les consommateurs viennent, ils commencent à lire le dernier message disponible et descendent quand ils le veulent sans que les producteurs le sachent.

J'ai la solution suivante en ce moment:

  1. Je crée une mémoire tampon circulaire d'entrées de taille fixe qui est écrit par un processus et lu par beaucoup. Le tampon circulaire est construit au-dessus d'un fichier mappé en mémoire dans/tmp.

  2. Le code de tampon circulaire est tel que les producteurs ne bloquent jamais l'attente de consommer des entrées par les consommateurs. Au lieu de cela, les consommateurs détectent le moment où la mémoire tampon annulaire est passée au milieu de la lecture/du traitement d'une entrée et rattrapent simplement la dernière. Je le fais avec quelques séquences de producteurs. Je peux développer ce point si nécessaire, mais cela ne me semble pas très pertinent. Ainsi, les producteurs galopent à toute vitesse et les consommateurs qui sont en retard détectent cette corruption en milieu de lecture et passent à la dernière entrée.

A partir de maintenant cela fonctionne très bien. Maintenant, j'essaie de comprendre comment ajouter de la signalisation au mixage afin que les consommateurs n'aient pas à tourner les séquences de lecture en attente d'un nouveau message. J'ai quelques exigences supplémentaires pour la partie de signalisation:

  1. La signalisation doit être une sorte de mécanisme de diffusion. Cela résulte de l'exigence d'un producteur/multiple_consumers. Donc, plusieurs processus devraient pouvoir être éveillés lorsque les producteurs les signalent. Étant donné que le producteur ne connaît aucun des consommateurs, il semble que nous ayons besoin d'une ressource nommée pour faire cette signalisation.

  2. Le mécanisme de signalisation doit pouvoir être composé avec d'autres signaux réguliers qui peuvent être attendus en utilisant select/epoll_wait. Les consommateurs qui lisent ce mécanisme IPC/ring_buffer attendent des écritures sur d'autres canalisations/sockets non apparentés, etc. et utilisent un select sur ces FDs. Il serait idéal de pouvoir produire une FD à partir de ce mécanisme que les consommateurs pourraient simplement ajouter à leur appel sélectif. De même, si le consommateur attend plusieurs ring_buffers de ce type, nous devons être en mesure de bloquer chacun d'entre eux et de se réveiller dès que l'un d'eux signale.

Avec ces exigences à l'esprit j'ai éliminé quelques options:

  1. Les variables de condition: Nous ne pouvons pas bloquer sur plusieurs de ces d'un consommateur. Ils ne sont pas non plus selectable.

  2. Tubes nommés: Nous aurions besoin d'un tube nommé par consommateur, ce qui implique une sorte de prise de contact producteur/consommateur que nous voulons éviter. Eventfd: les eventfds ne sont pas nommés, il semble donc qu'ils ne sont qu'une solution si la signalisation est entre les processus parents et enfants. Mon scénario a des processus qui sont démarrés indépendamment. Socket de domaine Unix: Il ne semble y avoir aucune installation de diffusion ici, donc je ne suis pas sûr si cela fonctionnera sans socket explicite par consommateur. Cela va à l'encontre de l'exigence de la poignée de main.

Je suis un peu perdu et je ne vois aucune autre bonne option. Pour moi, il semble que la multidiffusion UDP fonctionnera probablement. Les consommateurs peuvent tous faire partie d'un groupe de multidiffusion (créer une socket avec SO_REUSEADDR) et le producteur unique peut envoyer des messages sur ce groupe pour signaler les consommateurs. Mais cela semble vraiment lourd et complexe. Existe-t-il d'autres bons mécanismes pour y arriver? Je suis prêt à travailler directement avec le Futex API si cela aide aussi longtemps qu'il compose avec le blocage sur d'autres FD non liés en utilisant select/epoll.

Répondre

1

Je recommande d'envoyer un signal via DBus. Pourquoi lancer votre propre IPC, quand vous pouvez utiliser un framework mature qui fait déjà ce que vous voulez?

Cette page devrait vous aider à démarrer:

https://dbus.freedesktop.org/doc/dbus-tutorial.html

A la fin, il inclut des liens vers Qt et les API GLib. Je n'ai utilisé ni l'un ni l'autre, mais j'ai écrit mon propre wrapper basé sur Boost.ASIO autour de l'API de bas niveau, bien que ce soit une entreprise assez complexe.

https://dbus.freedesktop.org/doc/api/html/

BTW, pour envoyer des blocs de données binaires, vous aurez envie d'ajouter un arg de type DBUS_TYPE_ARRAY de DBUS_TYPE_BYTE, à votre message. Notez que DBUS_TYPE_STRING ne peut pas contenir d'octets zéro ou de séquences Unicode non valides.

Mise à jour: Une autre bibliothèque qui a récemment été portée à mon attention s'appelle sd-bus. Voici un bon aperçu & tutoriel:

http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html