(Voir Effo ci-dessous, et cette partie est obsolète) Le tampon circulaire n'est pas nécessaire s'il existe une file d'attente entre le thread et chaque interface utilisateur.
Lorsque le message est arrivé, le thread le fait glisser et le pousse dans la file d'attente de l'interface utilisateur en conséquence.
De plus, chaque UI.Q pourrait également fonctionner de manière atomique. Il n'y a pas de mutex nécessaire. Un autre avantage est que chaque message n'a été copié que deux fois: l'un est à bas niveau, l'autre à l'affichage, car il n'est pas nécessaire de stocker le message ailleurs (il suffit d'affecter un pointeur de la file d'attente bas à l'interface utilisateur. si C/C++).
Jusqu'à présent, la seule préoccupation est que pourrait la longueur d'un UI.Q est exécuté en temps ne suffit pas lorsque la messagerie est le trafic lourd. Pour cette question, vous pouvez utiliser une file d'attente de longueur dynamique ou laisser l'interface utilisateur elle-même stocker le message débordé dans un fichier mappé en mémoire posix. Rendement élevé si vous utilisez un mappage posix, même si vous utilisez un fichier et que vous avez besoin de copier davantage les messages. Mais de toute façon c'est seulement la gestion des exceptions. La file d'attente peut être définie à une taille appropriée afin que normalement vous obtiendrez d'excellentes performances. Le fait est que lorsque l'interface utilisateur doit stocker un message débordé dans un fichier mappé, elle doit également effectuer une opération hautement simultanée afin de ne pas affecter la file d'attente de bas niveau.
Je préfère la proposition de file d'attente de taille dynamique. Il semble que nous avons beaucoup de mémoire sur les PC modernes. Voir le document EffoNetMsg.pdf au http://code.google.com/p/effonetmsg/downloads/list pour en savoir plus sur les installations sans file d'attente, les files d'attente et les modèles de programmation hautement concurrents.
Effo EDIT @ 2009oct23: Afficher un modèle qui supporte un message Staged aléatoire d'accès pour le défilement des visionneuses de messages.
+---------------+
+---> Ring Buffer-1 <---+
| +---------------+ |
+--+ +-----+
| | +---------------+ | |
| +---> Ring Buffer-2 <---+ |
| +---------------+ |
| |
+-------+-------+ +-----------+----------+
| Push Msg & | | GetHeadTail() |
| Send AckReq | | & Send UpdateReq |
+---------------+ +----------------------+
|App.MsgStage() | | App.DisPlayStage() |
+-------+-------+ +-----------+----------+
| Pop() | Pop()
^ +-V-+ +-V-+
| Events | Q | Msg Stage | | Q | Display Stage
| Go Up | 0 | Logic-Half | | 1 | Logic-Half
-+------------- | | -------------+------------ | | ---------------
| Requests | | I/O-Half | | | I/O-Half
| Move Down +-^-+ | +-^-+
V | Push() |
+--------------+-------------+ |
| Push OnRecv Event, | +-------+-------+
| 1 Event per message | | | Push()
| | +------+------+ +------+------+
| Epoll I/O thread for | |Push OnTimer | |Push OnTimer |
|multi-messaging connections | | Event/UI-1 | | Event/UI-2 |
+------^-------^--------^----+ +------+------+ +------+------+
| | | | |
Incoming msg1 msg2 msg3 Msg Viewer-1 Msg Viewer-2
Les Points:
1 Vous COMPRENDRE différents modèles hautement simultanés, spécifique représenté sur la figure ci-dessus, un modèle; Mise en scène afin que vous sachiez pourquoi il fonctionne vite.
2 Deux types d'E/S, l'un est la messagerie ou Epoll thread si C/C++ et GNU Linux 2,6x; Une autre est Affichage tel que l'écran de dessin ou l'impression de texte, et ainsi de suite. Les 2 types d'E/S sont traités en 2 étapes en conséquence. Notez si Win/MSVC, utilisez le port d'achèvement au lieu de Epoll.
3 Encore 2 messages-copies comme mentionné précédemment. a) Push-OnRecv génère le message ("CMsg * pMsg = CreateMsg (msg)" si C/C++); b) l'interface utilisateur lit et copie le message de sa mémoire tampon en conséquence, et n'a besoin que de copier les parties de message mises à jour, et non le tampon entier. Les files d'attente de notes et les buffers en anneau stockent uniquement un descripteur de message ("queue.push (pMsg)" ou "RingBuff.push (pMsg)" si C/C++), et tout message d'expiration est supprimé ("pMsg-> Destroy() "si C/C++). En général, le MsgStage() reconstruire l'en-tête Msg avant de le pousser dans le tampon circulaire.
4 Après un événement OnTimer, l'interface utilisateur recevra la mise à jour de la couche supérieure qui contient de nouveaux indicateurs tête/queue du buff anneau. afin que l'interface utilisateur puisse mettre à jour l'affichage en conséquence. L'interface utilisateur de Hope a un tampon de messages locaux, il n'est donc pas nécessaire de copier l'ensemble de la mémoire tampon, mais juste de la mettre à jour. voir le point 3 ci-dessus. Si vous devez effectuer un accès aléatoire sur le tampon circulaire, vous pouvez simplement laisser l'interface utilisateur générer l'événement OnScroll. En fait, si l'interface utilisateur a un tampon local, OnScroll peut ne pas être nécessaire. de toute façon, vous pouvez le faire. Remarque L'interface utilisateur déterminera si elle doit ou non supprimer un message d'expiration, par exemple, générer un événement OnAgedOut, afin que les tampons d'anneau puissent être utilisés correctement et en toute sécurité.
5 Exactement, OnTimer ou OnRecv est le nom de l'événement, et OnTimer() {} ou OnRecv() {} serait exécuté dans DisplayStage() ou MsgStage(). Encore une fois, les événements vont vers le haut et les demandes vont en aval, et cela pourrait être différent de ce que vous aviez déjà vu ou vu.
6 Les tampons-anneaux Q0 et 2 peuvent être mis en œuvre sans verrou pour améliorer les performances, depuis un seul producteur et un seul consommateur; pas de verrou/mutex nécessaire. alors que Q1 est quelque chose de différent. Mais je crois que vous pouvez en faire un producteur unique et un consommateur unique en changeant légèrement le chiffre de conception ci-dessus, par ex. ajoutez Q2 pour que chaque UI ait une file d'attente, et DisplayStage() pourrait simplement interroger Q1 et Q2 pour traiter tous les événements correctement. Remarque Q0 et Q1 sont file d'attente d'événements, les files d'attente de requêtes ne sont pas affichées dans la figure ci-dessus.
7 MsgStage() et DisplayStage() sont dans un seul StagedModel.Stage() séquentiellement, disons le thread principal. Epoll I/O ou Messaging est un autre thread, le Thread MsgIO, et chaque UI a un thread d'E/S, par exemple Display Thread. Donc, dans la figure ci-dessus, il y a 4 threads au total qui s'exécutent simultanément. Effo a testé qu'un seul thread MsgIO devrait être suffisant pour les multi-liseners et des milliers de clients de messagerie.
Encore une fois, voir le document EffoNetMsg.pdf à http://code.google.com/p/effonetmsg/downloads/list ou EffoAddons.pdf à http://code.google.com/p/effoaddon/downloads/list pour en savoir plus sur les modèles de programmation hautement simultanées et la messagerie réseau; Pour en savoir plus sur les fonctionnalités sans verrou, telles que la file d'attente sans verrou et le tampon annulaire sans verrou, consultez EffoDesign_LockFree.pdf au http://code.google.com/p/effocore/downloads/list.
oui si je co-localise l'UI.Q à côté du code d'affichage, les choses sont peut-être plus faciles. C'est probablement encore mieux comme un tampon circulaire que les vieux trucs sont supprimés au débordement. L'interface utilisateur doit avoir un accès aléatoire à n'importe quelle partie de l'UI.Q pour le défilement de la fenêtre haut/bas. Je vais jeter un coup d'oeil à votre info de file d'attente sans verrou. – hplbsh
voir mes mises à jour, la figure ci-dessus. – Test