[LINUX] Communication inter-processus ~ mémoire partagée ~

Objectif

Pour rappel, j'ai résumé mes recherches sur la "mémoire partagée" en communication interprocessus (IPC).

L'article suivant a été très utile pour résumer la manière de communiquer entre les processus. J'ai également utilisé le code comme référence. Communication interprocessus Linux (Qiita)

L'environnement ici est le suivant. Le code est écrit en C ++. MacOS 10.13.4 gcc 7.3.0

Je vous serais reconnaissant si vous pouviez signaler les lacunes.

[Une addition] L'explication ci-dessous est la mémoire partagée de System V, et il semble que la mémoire partagée de POSIX existe également.

Commentaire

Qu'est-ce que la mémoire partagée?

Selon [Wikipedia](https://ja.wikipedia.org/wiki/shared memory), «la mémoire partagée est un moyen efficace d'échanger des données entre programmes». «Un processus est en mémoire et un autre processus. Créez une zone accessible depuis. " L'échange de données en utilisant une zone de mémoire serait un processus assez rapide. Cependant, il semble que vous deviez faire attention aux conflits car plusieurs processus peuvent accéder à la même mémoire.

Flux d'opération de mémoire partagée

L'important est que la mémoire partagée soit d'abord créée indépendamment du processus. Après cela, il sera lié à plusieurs processus.

Détails du fonctionnement de la mémoire partagée

Les fonctions suivantes sont fournies dans le système Unix pour gérer la mémoire partagée. shmget() (Man page of SHMGET) shmat() (Man page of SHMOP) shmdt() (Man page of SHMOP) shmctl() (Man page of SHMCTL) Veuillez lire chaque page de manuel pour plus de détails.

Ici, je n'expliquerai que les parties importantes.

shmget() Cette fonction est une fonction qui crée une mémoire partagée et émet son identifiant. Il permet également d'obtenir l'identifiant de la mémoire partagée déjà créée. Il faut trois arguments. ・ * Clé * Ceci est la clé IPC, qui peut être obtenue en utilisant ftok () ou ʻIPC_PRIVATE. Vous pouvez le considérer comme une valeur unique. Pour plus de détails, voir [Notions de base sur le système VIPC](https://www.ksworks.org/memo/net/sysv-ipc.html) et [Man Page of FTOK](https://linuxjm.osdn.jp/html/LDP_man) -Veuillez lire pages / man3 / ftok.3.html) et ainsi de suite. Cette clé est de type key_t, mais vous avez besoin de <sys / types.h>` pour l'utiliser.

· * Taille mémoire * Cela doit être un multiple de PAGE_SIZE. Si cela ne se produit pas, il semble qu'ils y remédieront en l'augmentant un peu.

· * Drapeau * Vous pouvez spécifier les options de création de mémoire partagée et les autorisations pour la mémoire créée. Pour plus de détails, voir Man Page. Il semble que vous puissiez utiliser des indicateurs pour définir des permissions (celles utilisées dans chmod) autres que celles listées ici.

Si vous souhaitez obtenir l'ID de la mémoire partagée créée, vous pouvez spécifier uniquement la clé et définir les autres sur 0.

shmat() Cette fonction attache la mémoire partagée créée à l'espace d'adressage du processus. Il faut trois arguments. ・ * ID de mémoire partagée * C'est la valeur créée et renvoyée par shmget ().

・ * Adresse mémoire * L'adresse à laquelle vous souhaitez attacher la mémoire partagée. Il semble que si vous définissez ceci sur 0, il sera sélectionné arbitrairement.

· * Drapeau * C'est pour spécifier les options. Pour plus de détails, veuillez lire Man Page.

shmdt() Cette fonction sépare la mémoire partagée de l'espace d'adressage du processus. Il semble qu'un seul argument soit requis et l'adresse renvoyée par shmat () est suffisante. C'est très facile.

shmctl() Cette fonction est utilisée pour effectuer divers contrôles concernant la mémoire partagée. Puisqu'il existe différentes fonctions, j'aimerais laisser les détails à Man Page. Il faut trois arguments. ・ * ID de mémoire partagée * L'ID de la mémoire partagée que vous souhaitez contrôler. C'est celui émis par shmget ().

·commander Il s'agit du contenu du contrôle que vous souhaitez effectuer sur la mémoire partagée. Dans cet article, nous utiliserons ʻIPC_RMID` pour libérer de la mémoire.

· * Pointeur vers la structure shmid_ds * C'est une structure pour stocker les informations que vous souhaitez ajouter à la mémoire partagée. Requis lors de l'utilisation de commandes telles que ʻIPC_STAT et ʻIPC_SET. Puisqu'il n'est pas nécessaire cette fois, laissez NULL (ou 0).

En fait utiliser

Je suis sûr que ce n'est pas grave si j'explique cela. Puisque je l'ai expliqué avec beaucoup d'efforts, je vais essayer de faire quelque chose qui fonctionne réellement. shm_a.cpp gère la mémoire partagée et y écrit n'importe quelle chaîne. shm_b.cpp lit et affiche le contenu écrit.

Exécutons les deux dans le même répertoire à partir de terminaux différents. Vous pouvez voir que le contenu écrit dans shm_a est également reflété dans shm_b.

shm_a.cpp


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
using namespace std;


int main(){
    //Créer un fichier vide
    FILE *fp;
    const string file_path = "./key.dat";
    fp = fopen(file_path.c_str(), "w");
    fclose(fp);

    //Obtention d'une clé IPC
    const int id = 50;
    const key_t key = ftok(file_path.c_str(), id);
    if(key == -1){
        cerr << "Failed to acquire key" << endl; 
        return EXIT_FAILURE;  
    }

    //Obtenir un identifiant de mémoire partagée
    const int size = 0x6400;
    const int seg_id = shmget(key, size, 
                              IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
    if(seg_id == -1){
        cerr << "Failed to acquire segment" << endl;
        return EXIT_FAILURE;
    }

    //Joindre la mémoire partagée à un processus
    char* const shared_memory = reinterpret_cast<char*>(shmat(seg_id, 0, 0));

    //Écrire dans la mémoire partagée
    string s;
    int flag = 0;
    cout << "if you want to close, please type 'q'" << endl;
    while(flag == 0){
        cout << "word: ";
        cin >> s;
        if(s == "q") flag = 1;
        else sprintf(shared_memory, s.c_str());
    }

    //Détacher la mémoire partagée du processus
    shmdt(shared_memory);

    //Libérez de la mémoire partagée
    shmctl(seg_id, IPC_RMID, NULL);    

    return 0;
}

shm_b.cpp


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
using namespace std;


int main(){
    //Obtenez l'ID de la mémoire partagée créée
	const string file_path = "./key.dat";
    const int id = 50;

    const key_t key = ftok(file_path.c_str(), id);

    const int seg_id = shmget(key, 0, 0);
    if(seg_id == -1){
        cerr << "Failed to acquire segment" << endl;
        return EXIT_FAILURE;
    }

    //Joindre la mémoire partagée à un processus
    char* const shared_memory = reinterpret_cast<char*>(shmat(seg_id, 0, 0));

    //Lire des caractères dans la mémoire partagée
    int flag = 0;
    char c;
    cout << "If you want to close, please type 'q'" << endl;
    cout << "If you want to read the shared memory, push enter button." << endl;
    while(flag == 0){
        cin.get(c);
        if(c == 'q') flag = 1;
        else printf("%s\n", shared_memory);
    }

    //Détacher la mémoire partagée du processus
    shmdt(shared_memory);

    return 0;
}

En cas de problème

Il existe ʻipcs comme commande pour gérer la communication entre les processus. Cela vous donnera des informations sur la mémoire partagée qui existe. Vous pouvez donc vérifier l'existence de la mémoire partagée en exécutant ʻipcs dans un autre terminal tout en exécutant shm_a.cpp. De plus, si la mémoire partagée n'est pas libérée correctement en arrêtant de force ce programme, vous pouvez la supprimer en utilisant ʻipcrm`. Veuillez lire le site suivant pour savoir comment l'utiliser. commande ipcs-IBM ipcrm --remove ID de communication interprocessus --IBM

référence

Recommended Posts

Communication inter-processus ~ mémoire partagée ~
Communication interprocessus Linux
Types de communication inter-processus
Mémoire partagée entre les processus
Utiliser la mémoire partagée avec une bibliothèque partagée
Communication interprocessus pour DL embarquée