Home  >  Article  >  Operation and Maintenance  >  How to implement Linux inter-process communication

How to implement Linux inter-process communication

王林
王林forward
2023-05-21 16:28:521602browse

    Shared memory

    • Shared memory can be said to be the most useful inter-process communication method and the fastest form of IPC. What different processes A and B share memory means: the same piece of physical memory is mapped to the respective process address spaces of processes A and B. Process A can see updates to the data in the shared memory by process B at the same time, and vice versa.

    • Since multiple processes share the same memory area, some kind of synchronization mechanism, mutex locks and semaphores are required.

    Benefits: High efficiency, the process can directly read and write memory without copying any data, while communication methods such as pipes and message queues require four times in the kernel and user space Data replication.

    And only when unmapping, the contents of the shared memory will be written to commemorate

    Shared memory uses kernel objects to enable different processes to allocate a space mapping on their own virtual address space To the same physical memory space, this physical memory space is accessible to every process mapped to it. (Critical resource)

    How to implement Linux inter-process communication

    Shared memory is allowing two unrelated processes to access the same logical memory.

    Shared memory is a very efficient way to share and transfer data between two running processes.

    Memory shared between different processes is usually arranged as the same segment of physical memory.

    Processes can connect the same segment of shared memory to their own address space, and all processes can access addresses in shared memory as if they were memory allocated using the C language function malloc().

    And if a process writes data to shared memory, the changes will immediately affect any other process that can access the same shared memory.

    mmap() and its related system calls

    mmap is a memory mapping function provided by the Linux operating system to the user space. Many people only know that memory sharing between processes can be completed through mmap. And reduce the number of data copies from user mode to kernel mode, but I don’t have a deep understanding of how mmap is implemented inside the operating system and what the principle is.

    How to implement Linux inter-process communication

    Use mmap() system Called, processes can share memory by mapping the same ordinary file. After an ordinary file is mapped to the process address space, the process can access the file like ordinary memory without calling read and write operations.

    Note: mmap is not completely designed for IPC. It is just an application method of IPC. It itself provides an access to ordinary files just like accessing ordinary memory. The way.

    Achieved by using virtual memory segments with special permission sets. When reading or writing this kind of virtual memory segment, the operating system will read and write the corresponding disk file part.

    Themmap function creates a pointer to a memory area associated with the contents of a file that can be accessed through an open file descriptor

    Explained below :

    mmap()

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

    You can change the starting offset value of data in the file accessed through the shared memory segment by passing the offset parameter.

    The open file descriptor is given by the fd parameter.

    The amount of data that can be accessed (that is, the length of the memory segment) is set by the length parameter.

    You can request the use of a specific memory address through the addr parameter. If its value is zero, the result pointer will be allocated automatically. Failure to follow this practice reduces the portability of your program because the available address ranges differ on different systems.

    The prot parameter is used to set the access permissions of the memory segment. It is the result of the bitwise OR of the following constant values

    • PROT_READ The memory segment is readable.

    • PROT_WRITE The memory segment is writable.

    • PROT_EXEC memory segment is executable.

    • PROT_NONE The memory segment cannot be accessed.

    #flags parameter controls the impact of the program's changes to the memory segment:

    How to implement Linux inter-process communication

    mmap() is used for shared memory The two methods are as follows:

    Use the memory mapping provided by ordinary files, which is suitable for any process. To use this method, you need to open or create a file first, and then call ngmmap. The typical calling code is as follows:

    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方法与该段连接。 

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

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

    How to implement Linux inter-process communication

    How to implement Linux inter-process communication

    完成下面的过程,

    How to implement Linux inter-process communication

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

    How to implement Linux inter-process communication

    #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

    The above is the detailed content of How to implement Linux inter-process communication. For more information, please follow other related articles on the PHP Chinese website!

    Statement:
    This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete