[win32]echange inter-processus via sharedmemory, mutex et event

Description

Un petit programme pour répondre à une question, :

http://www.delphifr.com/infomsg_EXECUTER-APPLI-CONSOLE-MM-TPS_1025052.aspx

Il permet de présenter quelques techniques intéressantes.

C'est un chat (Le truc sur internet, pas le machin avec des poils qui trolle). Sauf que là ça marche pas sur internet : les clients (Y a que des clients) doivent se trouver sur le même PC. Cherchez pas un intérêt autre que pédagogique, y en a pas.
Globalement, quand on tape des messages dans la console d'une instance du client, ils sont transmis aux autres instances.

Ce programme fait appel à 4 concepts :

#1 Les threads :

Ce n'est pas l'objet principal de ce source, mais comme j'en parle plus loin... Très connus les threads. Passez à la section suivante si vous avez déjà fait le tour de la question.

Le processeur exécute des portions de codes. Il exécute les lignes les unes après les autres sans se poser de question, comme quand on fait du débogage pas à pas. Par défaut, une application Delphi a un seul thread. A l'instant t, le processeur ne peut qu'exécuter une seule ligne, et l'instant d'après, il exécutera la suivante. Mais si on crée un deuxième thread, le processeur pourra exécuter simultanément deux lignes de codes (En fait non sur les processeurs qui sont en train de disparaître, mais c'est tout comme).

Dans cette application, le thread principal de l'application attend les entrées utilisateur dans la console. L'appel à ReadLn est dit bloquant. Pourtant, mon application a besoin de détecter quand les autres personnes connectées au chat envoie des message. C'est ça que mon deuxième thread va surveiller.

Dans Delphi, on peut faire des threads de deux manières différentes : soit en utilisant les fonctions de Windows, soit en héritant une classe de la classe TThread. Il n'y a pas de grosse différences entre les deux possibilités, si ce n'est que TThread compile certainement sous Kylix (La version Linux de Delphi), tout en ne pénalisant certainement pas trop les performances tant elle est proche de l'implémentation Windows.

J'ai utilisé TThread, mais pour le reste, je suis passé par du Win32.

#2 Les vues de fichiers (FileMapping) :

Quand on demande à Windows de nous donner une vue d'un fichier, il va nous permettre d'écrire dans ce fichier (Ou des bouts de celui-ci) comme s'il se trouvait dans la RAM.

Dans ce programme, on se sert du FileMapping sans fichier : Windows renvoie une zone mémoire accociée à aucun fichier sur le disque.

On parle alors plutôt de mémoire partagée (SharedMemory). L'avantage de ce type de mémoire est que différents processus vont pouvoir y accéder presque comme si celle-ci avait été allouée par eux.

En effet, chaque processus vit dans son petit monde avec ses 4Go d'espace adressable (Les pointeurs faisant 32bits). Les adresses que l'on utilise son virtuelles et ne sont pas interchangeables entre les processus. Et on ne peut pas non plus retrouver les variables du processus voisin en cherchant dans la mémoire du processus courant. Les SharedMemory se présente donc comme une bonne méthode de partage de données.

D'autres procédés d'échanges de mémoires entre processus existent : on peut par exemple utiliser de simples fichiers, des pipes, les fonctions Read/WriteProcessMemory...

Dans ce programme, les différents processus (Toutes des instances d'un même executable, en d'autre mots, on a double cliqué plusieurs fois sur le .exe), vont mettre les messages dans une SharedMemory. Ainsi, les autres processus pourront afficher les messages dans leurs propres consoles.

Windows nous fournit une zone de la taille que l'on veut, à nous de la gérer. Ca risque de passer par des pointeurs et quelques transtypages bien sentis. Donc faut pas faire n'importe quoi et réfléchir un peu. Dans cette application, j'ai décidé de réserver les 4 premiers octets (Taille d'un integer) pour sauvegarder la taille de la chaîne contenue dans la SharedMemory. La chaîne en elle même se trouve juste après ces 32bits (Voir l'incrémentation du pointeur dans le code). On peut mettre des structures et des tableaux sans problèmes en étant un peu inventif. Pour les objets par contre, faut pas espérer y parvenir sans s'y connaître pas mal (Savoir ce qu'est une vtable par exemple...).

#3 Les évènements (event) :

Les évènements utilisés ne sont pas ceux de Delphi, et pas non plus ceux utilisés quand on parle de programmation évènementielle sous Windows. Simples d'emploi, ils permettent de signaler à des threads des heu... évènements.

Dans notre cas, l'évènement, c'est l'écriture d'un nouveau message dans la SharedMemory. Le deuxième thread va attendre patiemment cette évènement à l'aide d'une fonction très utile qui s'appelle WaitForSingleObject. On aurait pu utiliser un timer mais l'attente sur évènement est bien plus simple et efficace dans ce cas. Le plus dur est de savoir que ça existe...

#4 Les mutexs :

Une mémoire partagée, que ce soit par plusieurs threads d'un même processus, ou par plusieurs processus, ça peut poser problème.

En effet, comme deux thread peuvent s'exécuter en même temps, 2 d'entres eux peuvent essayer d'écrire au même endroit en même temps... Et là le résultat risque de pas être beau à voir.

Pour ceux qui connaissent, les mutexs permettent de faire des sections critiques manuellement. Ils sont moins performant que les sections critiques de Windows, mais celles-ci ne fonctionnent pas entre plusieurs processus.

Les mutexs vont nous permettre de nous assurer que 2 threads ne tentent pas d'accéder au même endroit en même temps. Concrètement, le mutex est un peu comme un jeton dans un verre. Deux personnes peuvent prendre le jeton. Quand l'une à le jeton, l'autre ne peut pas l'avoir aussi. Les mutexs, c'est pareil : on demande au thread de prendre le jeton, ou d'attendre jusqu'à ce qu'il soit disponible.

Cela peut poser problème si une personne qui a le jeton décide de partir boire un pastis avec celui-ci... On peut aussi arriver à des situations assez folkloriques où tout le monde attend attend tout le monde pour continuer son execution. On appele ça les deadlocks. Comme avec les pointeurs, là aussi faut faire un peu gaffe.

PS : Sur le screenshot, c'est pas des citations et faut pas chercher de cohérence. C'est normal que l'on ai l'impression que des messages apparraissent deux fois : une fois quand l'utilisateur les tapes, et une deuxième quand la mémoire partagée est lue.

Source / Exemple :


Le zip...

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.