Bibliothèque sous-jacente multiplateforme https://github.com/hujianzhe/util, téléchargez-la et placez-la dans le répertoire BootServer
Introduction:
Le code implémente uniquement le démarrage du nœud de service, la planification des tâches et la description de base des modules. Il ne contient aucun code métier. Il est implémenté en C pur. Il est généralement compilé dans une bibliothèque dynamique et reste extrêmement restreint en termes de fonctions d'utilisation. Il implémente certains flux de protocole communs et prend en charge C++ 20 Extension de coroutine sans pile et isolé de certains codes de bibliothèque dynamique C pur pour empêcher C++ de contaminer la couche framework et d'affecter la génération de bibliothèque dynamique.
Le code dans util est responsable du multiplateforme, sauf qu'il ne nécessite pas l'installation de bibliothèques tierces.
Introduction au processus de fonctionnement :
Le processus métier appelle la bibliothèque dynamique compilée par le code et appelle l'interface correspondante à utiliser. Pour plus de détails sur le processus appelant, voir l'exemple de nœud de test (main_template dans le répertoire BootServer est un ensemble de modèles de code de démarrage basés sur le processus).
Plusieurs threads gèrent la lecture et l'écriture des E/S réseau à l'intérieur du module. Un thread d'acceptation d'accès distinct ouvrira initialement un thread de travail pour traiter les messages internes et les messages réseau reçus et les distribuera à la logique de votre code métier. Le thread de travail utilise une coroutine de pile pour planifier le traitement (voir ci-dessous la raison pour laquelle une coroutine sans pile n'est pas utilisée)
Les threads de travail utilisent des coroutines de pile pour la planification par défaut afin de maintenir la compatibilité la plus élevée. Vous pouvez également facilement utiliser des coroutines sans pile C++ 20 (une implémentée dans la bibliothèque util) pour la planification. Il existe des coroutines de pile et des processus de coroutines sans pile peuvent coexister.
Introduction du module et exemple de code :
1. BootServer : partie principale du code, initialisation et fonctionnement nécessaires des nœuds de service
2. ServiceTemplate : modèle de code de nœud de service, utilisé pour écrire votre logique métier
3. SoTestClient, SoTestServer : tester les nœuds et écrire quelques exemples de codes
4. Cpp20-SoTestServer : nœud de test, écrit un exemple de code, activé la coroutine sans pile C++20 dans main.cpp (en utilisant un planificateur de coroutine sans pile C++20 dans la bibliothèque util)
Compiler:
Compilation VS directe Windows
Utilisez make debug / make release / make asan sous Linux/Mac OS X
démarrer:
Modifiez le fichier de configuration requis pour le démarrage du nœud de service (voir le modèle de fichier de configuration ci-joint pour le format spécifique) et attribuez à chaque nœud un fichier de configuration et un identifiant unique, un nom d'identification du journal, une adresse IP et un numéro de port.
Windows s'ouvre directement dans VS et le projet est configuré avec les paramètres de démarrage <fichier de configuration>
Une fois Linux/Mac compilé, sh run.sh <service process> <fichier de configuration>
Quelques raisons et idées de conception : Q : Pourquoi ne pas utiliser des coroutines sans pile mais plutôt des coroutines empilées ? R : Il est facile d'implémenter des coroutines sans pile en C pur (pour un code détaillé, vous pouvez voir le planificateur de coroutines sans pile implémenté en C pur dans la bibliothèque util), mais le recyclage et la persistance des ressources (en particulier les variables sur la pile sont soumises à la coroutine). -entrée). (cette dernière situation) est extrêmement difficile Si vous souhaitez utiliser les coroutines sans pile en douceur, vous devez toujours compter sur la prise en charge du compilateur. Ceci a été réalisé en C++20. Il existe également une implémentation complète du planificateur de coroutines sans pile C++20 dans la bibliothèque util.
Q : Pourquoi la coroutine sans pile fournit-elle cette fonction étendue sous la forme d'un fichier d'en-tête ?
R : 1. Parce que les coroutines sans pile sont intrusives dans le code et modifieront un grand nombre de formes de signature de fonction.
2. Contient des objets C++ qui ne sont pas reconnus en C et la bibliothèque dynamique ne peut pas être exportée avec succès.
3. Donné sous la forme d'un fichier d'en-tête, transmettre l'autorisation d'activation des coroutines sans pile à la couche application est la façon dont je pense actuellement pour gérer la partie bibliothèque dynamique C pure sans aucune pollution.
Q : Peut-il être remplacé par d’autres planificateurs ?
R : Le planificateur du thread de travail peut être remplacé. Le thread de travail est conçu comme le support d'exécution du planificateur. L'interaction entre le thread réseau et le thread de travail dans le cadre peut correspondre au comportement de planification via le hook d'interface.
Q : Peut-il être remplacé par d’autres bibliothèques réseau ?
R : 1. Elle ne peut pas être remplacée par d'autres bibliothèques réseau pour le moment, mais ce problème a été pris en compte au début de la conception. La partie réseau et la partie planification des tâches sont complètement séparées. À l'avenir, les comportements correspondants sont similaires au thread de travail. des crochets seront fournis pour le remplacement.
2. Bien qu'il existe de nombreuses bibliothèques réseau tierces, leurs objectifs sont différents. Il existe des bibliothèques TCP et UDP utilisées pour le développement d'applications, il existe également des bibliothèques qui souhaitent inclure l'univers entier, et il existe également des bibliothèques qui implémentent l'intégralité de la pile de protocoles réseau au niveau de la couche application, donc en fait ce domaine n'est pas unifié.
3. Si un ensemble de bibliothèques réseau entre dans la norme à l'avenir, je le remplacerai.
Q : Pourquoi ne pas simplement utiliser C++ comme framework ?
R : 1. Lorsque cet ensemble de code a été écrit, C++20 n'était pas encore apparu, la solution de coroutine relativement la plus mature était la coroutine de pile. Cela pouvait être fait en utilisant C en appelant l'API système de plate-forme correspondante.
2. Les fonctions à implémenter par ce type de framework ont été solidifiées, et le cycle de vie des ressources est solidifié par le processus. Il suffit juste de l'implémenter en C pur (il y avait une version implémentée en C++ avant, et la). le code était plus compliqué)
3. Si la bibliothèque dynamique est appelée par d'autres modules, elle doit encore sceller une interface en C
4.Les classes exportées C++ sont contagieuses et l'ABI n'est pas unifiée
Q : La couche métier peut-elle continuer à être développée en C pur ?
R : C'est fortement déconseillé, car l'écriture de processus asynchrones et d'exceptions lancées dans des modules écrits dans des langages de haut niveau rendent incertain le moment de la destruction des ressources. À l'heure actuelle, il est extrêmement difficile de contrôler manuellement les ressources en utilisant du C pur. . Vous devez utiliser un langage de niveau supérieur pour gérer ces choses. Par exemple, vous pouvez utiliser C++ pour développer du code métier de niveau supérieur, et son mécanisme RAII peut garantir la libération des ressources correspondantes.
Q : Si je souhaite transformer le « callback » de l'ancien projet en « coroutine », puis-je simplement remplacer la partie planificateur par le point d'appel correspondant dans le code métier ?
R : Ce n'est pas si simple. Le premier est le problème de la charge de travail. De plus, que ce soit sous forme de rappel ou de coroutine, l'essentiel est d'émettre une demande et d'attendre le résultat pendant cette période. est un problème qui doit être résolu et soigneusement examiné. S'il s'agit d'un pointeur brut, on peut presque dire qu'il ne peut pas être transformé si le projet l'a utilisé. Des moyens tels que std::shared_ptr allongent le cycle de vie des variables, il sera donc moins difficile de les transformer en une version "stack coroutine". Si vous souhaitez vous transformer en une coroutine sans pile C++20, la charge de travail est énorme. équivaut à réécrire le projet (car les coroutines sans pile ont une forte intrusion de code), il est donc recommandé de ne pas transformer les anciens projets.
Q : Pourquoi la coroutine n'est-elle actuellement pas autorisée à migrer vers différents threads pour exécution ?
R : La migration des coroutines peut être effectuée facilement, mais la raison pour laquelle elle n'est pas fournie est
1. Les tâches exécutées entre les coroutines sont incertaines, ce qui peut entraîner le mélange des io et des calculs dans le même thread de planification.
2. Après la migration, le même processus coroutine peut s'exécuter sur différents threads. Dans ce cas, vous devez vous assurer que votre code ne repose sur aucune variable locale de thread, mais vous ne pouvez pas garantir que la bibliothèque tierce n'utilise pas de variables locales de thread. .
Q : Asan va-t-il planter lors de la compilation et de l'exécution ?
R : 1. Si vous utilisez la coroutine empilée par défaut du framework, ce n'est certainement pas un problème de code. Vous pouvez ajuster la taille de la pile de coroutines empilées dans le fichier de configuration du nœud (lorsque ASAN est activé, un espace de pile relativement important sera consommé). il y a donc une possibilité d'explosion de pile)
2. ASAN ne prend pas entièrement en charge l'API de coroutine empilée (ucontext) dans l'environnement Unix. Bien que l'API de coroutine ucontext ait été adaptée à ASAN dans le code utilitaire, elle ne peut toujours pas garantir à 100 % qu'il n'y aura aucun problème d'exécution dans ASAN. environnement (jusqu’ici tout va bien).
3. Dans certaines distributions Linux plus récentes, si ASAN génère AddressSanitizer: DEADLYSIGNAL à l'infini, ajustez sudo sysctl vm.mmap_rnd_bits=28 pour résoudre le problème.
FAIRE:
1. Je n’ai vraiment pas le temps de rédiger une documentation détaillée.
2. Fournir un support pour l'écriture de la logique métier dans un langage de script