Maison  >  Article  >  Opération et maintenance  >  Comment implémenter la communication inter-processus Linux

Comment implémenter la communication inter-processus Linux

王林
王林avant
2023-05-21 16:28:521686parcourir

    Mémoire partagée

    • La mémoire partagée peut être considérée comme la méthode de communication inter-processus la plus utile et la forme la plus rapide d'IPC. Ce que signifient deux processus différents A et B partagent la mémoire : la même mémoire physique est le mappage. Aux espaces d'adressage de processus respectifs des processus A et B, le processus A peut voir les mises à jour des données dans la mémoire partagée par le processus B en même temps, et vice versa.

    • Étant donné que plusieurs processus partagent la même zone de mémoire, une sorte de mécanisme de synchronisation, de verrous mutex et de sémaphores sont nécessaires.

    Avantages : Haute efficacité, le processus peut lire et écrire directement la mémoire sans copier de données, tandis que les méthodes de communication telles que les canaux et les files d'attente de messages nécessitent quatre copies de données dans le noyau et l'espace utilisateur.

    Et seulement lors du démappage, le contenu de la mémoire partagée sera commémoré.

    La mémoire partagée utilise des objets du noyau pour permettre à différents processus d'allouer un espace dans leur propre espace d'adressage virtuel et de le mapper au même espace mémoire physique. l'espace mémoire est accessible à chaque processus qui y est mappé. (Ressource critique)

    Comment implémenter la communication inter-processus Linux

    La mémoire partagée permet à deux processus non liés d'accéder à la même mémoire logique.

    La mémoire partagée est un moyen très efficace de partager et de transférer des données entre deux processus en cours d'exécution.

    La mémoire partagée entre différents processus est généralement organisée comme le même morceau de mémoire physique.

    Les processus peuvent connecter le même segment de mémoire partagée dans leur propre espace d'adressage, et tous les processus peuvent accéder aux adresses de la mémoire partagée comme s'il s'agissait de mémoire allouée à l'aide de la fonction malloc() du langage C.

    Et si un processus écrit des données dans la mémoire partagée, les modifications affecteront immédiatement tout autre processus pouvant accéder à la même mémoire partagée.

    mmap() et ses appels système associés

    mmap est une fonction de mappage de mémoire fournie par le système d'exploitation Linux pour être appelée par l'espace utilisateur. Beaucoup de gens savent seulement que mmap peut être utilisé pour compléter le partage de mémoire entre les processus et réduire le mode utilisateur. en mode noyau. Le nombre de copies de données, mais il n'y a pas de compréhension approfondie de la façon dont mmap est implémenté dans le système d'exploitation et quel est son principe. En utilisant l'appel système mmap(), les processus peuvent réaliser le partage de mémoire en mappant la même chose. fichier ordinaire. Une fois qu'un fichier ordinaire est mappé à l'espace d'adressage du processus, le processus peut accéder au fichier comme une mémoire ordinaire sans appeler d'opérations de lecture et d'écriture.

    Comment implémenter la communication inter-processus LinuxRemarque :

    mmap n'est pas entièrement conçu pour IPC, c'est juste une méthode d'application d'IPC. Il fournit lui-même un moyen d'accéder aux fichiers ordinaires comme accéder à la mémoire ordinaire.

    Obtenu en utilisant des segments de mémoire virtuelle avec des ensembles d'autorisations spéciaux. Lors de la lecture ou de l'écriture de ce type de segment de mémoire virtuelle, le système d'exploitation lira et écrira la partie de fichier disque correspondante. La fonction

    mmap crée un pointeur vers une zone mémoire associée au contenu d'un fichier accessible via un descripteur de fichier ouvert

    s'explique comme suit :

    mmap()

    #include <sys/mman.h>
    
    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

    peut être passée par le paramètre offset pour modifier la valeur de décalage de départ des données dans le fichier accessible via le segment de mémoire partagée.

    Le descripteur de fichier ouvert est donné par le paramètre fd.

    La quantité de données accessibles (c'est-à-dire la longueur du segment de mémoire) est définie par le paramètre de longueur.

    Vous pouvez demander l'utilisation d'une adresse mémoire spécifique via le paramètre addr. Si sa valeur est zéro, le pointeur de résultat sera alloué automatiquement. Le non-respect de cette pratique réduit la portabilité de votre programme car les plages d'adresses disponibles diffèrent selon les systèmes. Le paramètre

    prot est utilisé pour définir les autorisations d'accès au segment mémoire. C'est le résultat du OU au niveau du bit des valeurs constantes suivantes

    PROT_READ Le segment mémoire est lisible.

    • PROT_WRITE Le segment mémoire est inscriptible.

    • Le segment de mémoire PROT_EXEC est exécutable. Le segment de mémoire

    • PROT_NONE n'est pas accessible. Le paramètre

    • flags contrôle l'impact des modifications du programme sur le segment de mémoire :

    mmap() est utilisé pour partager la quantité de mémoire et les deux méthodes sont les suivantes :

    Utilisez le mappage mémoire fourni par des fichiers ordinaires, applicables Entre n'importe quel processus, l'utilisation de cette méthode nécessite d'abord d'ouvrir ou de créer un fichier, puis d'appeler ngmmap. Le code d'appel typique est le suivant : Comment implémenter la communication inter-processus Linux.

    fd = open(name.falg.mode);
    if(fd < 0)
    ptr = mmap(NULL,len.PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

    使用特殊文件提供的内存映射,适用于具有亲缘关系的进程之间,由于父子进程特殊的亲缘关系,在父进程中先调用mmap,调用fork,那么在代用fork之后,子进程可以继承父进程匿名映射后的地址空间,同样也继承mmap返回的地址,这样父子进程就可以通过映射区域进行通信了。(注意:一般来说,子进程单独维护从父进程继承而来的一些变量,而mmap()返回的地址由父子进程共同维护)【具体使用实现敬请期待博主整理】

    munmap()

    用于解除内存映射,取消参数start所指的映射内存的起始地址,参数length则是欲取消的内存大小,当进程结束或者利用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述符时不会解除映射。

    #include <sys/mman.h>
    
    int munmap(void *addr, size_t length);

    共享内存的使用

    与信号量一样,在Linux中也提供了一组函数接口用于使用共享内存,而且使用共享共存的接口还与信号量的非常相似,而且比使用信号量的接口来得简单。它们声明在头文件 sys/shm.h 中。 

    1.获取或创建内核对象,并且制定共享内存的大小(系统分配物理空间是,按照页进行分配)

    int shmget(key_t key, int size, int flag);

    只是创建内核对象,并申请物理空间

    • key_t key:与信号量的semget函数一样,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,不同的进程通过相同的key值来访问同一块共享内存

    • int size:size以字节为单位指定需要共享的内存容量

    • int flag:falg是权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。

    返回值

    • 调用成功后,shmget()函数会返回一个非负整数,用作后续共享内存函数的共享内存标识符,该标识符与key相关。

    • 调用失败返回-1.

    2.分配自己虚拟地址空间映射到共享内存的物理空间上

    void *shmat(int shmid,const void *addr, int flag);
    • shmid:shmid是由shmget()函数返回的共享内存标识。

    • void *addr:addr指定共享内存连接到当前进程中的地址位置,通常为NULL,表示让系统来选择共享内存的地址。

    • int flag:flag是一组标志位,通常为0。

    调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1.

    3.断开当前进程与共享内存的映射

    不使用删除而使用断开的原因是因为:也许还存在其他的进程会继续使用这块共享内存

    int shmdt(const void *addr);

    4.操作共享内存的方法

    int shmctl(int shmid, int cmd, struct shmid_t *buf);
    • int shmid:shmid是shmget()函数返回的共享内存标识符。

    • int cmd:command是要采取的操作,它可以取下面的三个值 :

    IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。

    IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值

    IPC_RMID:删除共享内存段

    • struct shmid_t *buf:buf是一个结构指针,它指向共享内存模式和访问权限的结构

    因为有连接计数器,除非最后一个进程与该共享段断开连接,则删除该共享段。否则,并不会真正删除该共享段,但是共享内存的内核对象会被立即删除,不能使用shmat方法与该段连接。 

    一个进程调用该方法删除后,不会影响之前已经和该共享存储段连接的进程

    下面我们利用共享内存来进行一个简单的测试:

    Comment implémenter la communication inter-processus Linux

    Comment implémenter la communication inter-processus Linux

    完成下面的过程,

    Comment implémenter la communication inter-processus Linux

    成功在共享内存中读到了数据

    Comment implémenter la communication inter-processus Linux

    #include<stdio.h>
    #include<stdlib.h>
    #include<assert.h>
    #include<string.h>
    #include<unistd.h>
    
    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    
    #include"sem.h"
    
    #define READSEM 1
    #define WRITESEM 0
    
    int main()
    {
    	int shmid = shmget((key_t)1234,128,0664 | IPC_CREAT);
    	assert(shmid != -1);
    
    	char *ptr = (char*)shmat(shmid,NULL,0);
    	assert(ptr != (char*)-1);
    	
    	int initVal[] = {1,0};
    	int semid = SemGet(1234,intVal,2);
    	assert(semid != -1);
    	
    	//A进程写
    	while(1)
    	{
    		SemP(semid,WRITESEM);
    		printf("Input:");
    		
    		fgets(ptr,127,stdin);
    		
    		SemV(semid,READSEM);
    		
    		if(strncmp(ptr,"end",3) == 0)
    		{
    			break;
    		}
    	}
    	
    	shmdt(ptr);
    	exit(0);
    }
    #include<stdio.h>
    #include<stdlib.h>
    #include<assert.h>
    #include<string.h>
    #include<unistd.h>
    
    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    
    #include"sem.h"
    
    #define READSEM 1
    #define WRITESEM 0
    
    int main()
    {
    	int shmid = shmget((key_t)1234,128,0664 | IPC_CREAT);
    	assert(shmid != -1);
    
    	char *ptr = (char*)shmat(shmid,NULL,0);
    	assert(ptr != (char*)-1);
    	
    	int initVal[] = {1,0};
    	int semid = SemGet(1234,intVal,2);
    	assert(semid != -1);
    	
    	//B进程读
    	while(1)
    	{
    		SemP(semid,READSEM);
    		
    		if(strncmp(ptr,"end",3) == 0)
    		{
    			break;
    		}
    		
    		int i = 0;
    		for(;i < strlen(ptr) - 1;i++)
    		{
    			printf("%c",toupper(ptr[i]));
    			fflush(stdout);
    			sleep(1);
    		}
    		printf("\n");
    		SemV(semid,WRITESEM);
    	}
    	
    	shmdt(ptr);
    	exit(0);
    }

    从上面的代码中我们可以看出: 

    共享内存是最快的IPC,在通信过程中少了两次数据的拷贝。(相较于管道)

    命令管理共享内存

    • 查看 ipcs -m

    • 删除 ipcrm -m shmid

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer