Inter-Process Communication (IPC) Methods (b)

Inter-Process Communication (IPC) Methods (b)

Shared Memory (SHARE MEMORY)

  • Allows multiple processes can be directly read and write the same memory space, it is the fastest form of IPC available. For other communication mechanism is not efficient design.
  • To exchange information between multiple processes, kernel set aside a piece of memory area can be accessed by the process needs to be mapped to its own private address space. This process can directly read and write memory without the need for a copy of the data, thus greatly improving efficiency.
  • Because multiple processes to share some memory, and therefore need to rely on some kind of synchronization mechanism (such as semaphores) to achieve synchronization and mutual exclusion between processes.

Shared memory

Linux kernel supports a variety of shared memory, such as mmap () system call, Posix shared memory, and System V shared memory.

mmap

mmap () system call allows processes between shared memory by mapping with a common file. After the general file is mapped into the process address space, the process can be as accessible as normal memory access to files, do not have to call the read (), write () and so on.

Note: In fact, mmap () system call is not entirely used for shared memory and design. It itself provides a way different from the general access to common files, the process can be like memory read and write operations on a regular file. The Posix or System V shared memory IPC is purely for the purpose of sharing, of course mmap () shared memory is also one of its main application.

mmap schematic

Use of mmap
#include <sys/mman.h>
void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset); 
  • Returns: Success: returns the first address mapping area created; failure: MAP_FAILED Macro
  • parameter:
    • addr: the establishment of the first address mapping area, designated by the Linux kernel. In use, the passthrough NULL
    • length: To create the size of the map area
    • prot: mapping area authority PROT_READ, PROT_WRITE, PROT_READ | PROT_WRITE
    • flags: Flag parameter (often used to set the update physical area, set the share, create an anonymous mapping area)
      • MAP_SHARED: what you did mapped area will be reflected on the physical devices (disk).
      • MAP_PRIVATE: modify the mapping area are not reflected to the physical device.
    • fd: file descriptor used to build the mapping area
    • offset: offset map file (4k integer multiple)

Malloc function with a similar application memory space, mmap mapped area established after the end of use should also be called to release a similar free function.

int munmap(void *addr, size_t length);  //成功:0; 失败:-1

eg.

// 写共享内存
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

typedef struct
{
    char name[32];
    int age;
} people;

int main(int argc, char** argv)
{
    if(argc < 2)
    {
         fprintf(stderr,"Usage: %s filename \n", argv[0]);
         return -1;
    }
    people* p_map;
    char temp = 'a';
    
    int fd = open(argv[1], O_CREAT|O_RDWR|O_TRUNC, 00777);
    if (-1 == fd)
    {
        printf("open file error = %s\n", strerror(errno));
        return -1;
    }
    ftruncate(fd, sizeof(people)*10);
    p_map = (people*)mmap(NULL, sizeof(people)*10, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == p_map)
    {
        printf("mmap file error = %s\n", strerror(errno));
        return -1;
    }
    
    for(int i = 0; i < 10; i++)
    {
        memcpy( (*(p_map+i)).name, &temp, 1);
        (*(p_map+i)).name[1] = 0;
        (*(p_map+i)).age = 20+i;
        temp += 1;
    }
    printf("initialize over\n");
        
    close(fd);
    munmap(p_map, sizeof(people)*10);
    printf("umap ok \n");
    return 0;
}

// 读共享内存
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

typedef struct
{
    char name[32];
    int age;
} people;

int main(int argc, char** argv)
{
    if(argc < 2)
    {
         fprintf(stderr,"Usage: %s filename \n", argv[0]);
         return -1;
    }
    people* p_map;
    struct stat filestat;
    
    int fd = open(argv[1], O_CREAT|O_RDWR, 00777);
    if (-1 == fd)
    {
        printf("open file error = %s\n", strerror(errno));
        return -1;
    }
    fstat(fd, &filestat);
    p_map = (people*)mmap(NULL, filestat.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == p_map)
    {
        printf("mmap file error = %s\n", strerror(errno));
        return -1;
    }
    
    for(int i = 0; i < 10; i++)
    {
        printf("name = %s, age = %d\n",(*(p_map+i)).name, (*(p_map+i)).age);
    }
    
    close(fd);
    munmap(p_map, sizeof(people)*10);
    printf("umap ok \n");
    return 0;
}

operation result:

执行./mmap_w people.txt

mmap_w

执行./mmap_r people.txt

mmap_w

POSIX shared memory

POSIX shared memory using the method has the following two steps:

  1. By shm_opencreating or opening a POSIX shared memory object
  2. Call to mmapmap it to the current process address space

And using the communication performed by the memory-mapped file descriptor mmap difference is not the same acquisition parameters: through open or shm_open. POSIX POSIX message queues and shared memory, known as semaphores having characteristics are sustainable with the kernel.

POSIX shared memory usage
#include <sys/mman.h>
#include <sys/stat.h>        /* For mode constants */
#include <fcntl.h>           /* For O_* constants */

// 打开一个共享内存的文件句柄
int shm_open(const char *name, int oflag, mode_t mode);
//注意 这里的名字具有形式 /somename,即必须以 / 为开头,因为POSIX共享内存对应的文件是位于/dev/shm这个特殊的文件系统内。

// 删除一个共享内存的名字,但只有所有程序都关闭,才会真的删除
int shm_unlink(const char *name);

eg.

Write shared memory

#include <sys/mman.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

typedef struct
{
    char name[32];
    int age;
} people;

main(int argc, char** argv)
{
    if(argc < 2)
    {
         fprintf(stderr,"Usage: %s /filename \n", argv[0]);
         return -1;
    }
    people* p_map;
    char temp = 'a';
    
    int fd = shm_open(argv[1], O_CREAT|O_RDWR, 00777);
    if (-1 == fd)
    {
        printf("open file error = %s\n", strerror(errno));
        return -1;
    }
    ftruncate(fd, sizeof(people)*10);
    p_map = (people*)mmap(NULL, sizeof(people)*10, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == p_map)
    {
        printf("mmap file error = %s\n", strerror(errno));
        return -1;
    }
    
    for(int i = 0; i < 10; i++)
    {
        memcpy( ( *(p_map+i) ).name, &temp, 1);
        ( *(p_map+i) ).name[1] = 0;
        ( *(p_map+i) ).age = 20+i;
        temp += 1;
    }
    printf("initialize over\n");
        
    close(fd);
    munmap(p_map, sizeof(people)*10);
    printf("umap ok \n");
    return 0;
}

Reading shared memory

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

typedef struct
{
    char name[32];
    int age;
} people;

main(int argc, char** argv)
{
    if(argc < 2)
    {
         fprintf(stderr,"Usage: %s /filename \n", argv[0]);
         return -1;
    }
    people* p_map;
    struct stat filestat;
    
    int fd = shm_open(argv[1], O_CREAT|O_RDWR, 00777);
    if (-1 == fd)
    {
        printf("open file error = %s\n", strerror(errno));
        return -1;
    }
    fstat(fd, &filestat);
    p_map = (people*)mmap(NULL, filestat.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == p_map)
    {
        printf("mmap file error = %s\n", strerror(errno));
        return -1;
    }
    
    for(int i = 0; i < 10; i++)
    {
        printf("name = %s, age = %d\n",(*(p_map+i)).name, (*(p_map+i)).age);
    }
    
    close(fd);
    munmap(p_map, sizeof(people)*10);
    printf("umap ok \n");
    return 0;
}

Delete shared memory

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

main(int argc, char** argv)
{
    if(argc < 2)
    {
         fprintf(stderr,"Usage: %s /filename \n", argv[0]);
         return -1;
    }
    int ret = shm_unlink(argv[1]);
    if (-1 == ret)
    {
        printf("unlink shm error = %s\n", strerror(errno));
        return -1;
    }
    
    printf("unlink ok \n");
    return 0;
}

operation result:

[root@rocket ipc]# g++ -g -o ipc_posix_mmap_writer ipc_posix_mmap_writer.cpp -lrt
[root@rocket ipc]# ./ipc_posix_mmap_writer /shm_from_mem.txt
initialize over
umap ok
[root@rocket ipc]# g++ -g -o ipc_posix_mmap_reader ipc_posix_mmap_reader.cpp -lrt
[root@rocket ipc]# ./ipc_posix_mmap_reader /shm_from_mem.txt
name = a, age = 20
name = b, age = 21
name = c, age = 22
name = d, age = 23
name = e, age = 24
name = f, age = 25
name = g, age = 26
name = h, age = 27
name = i, age = 28
name = j, age = 29
umap ok
[root@rocket ipc]# ./ipc_posix_mmap_unlink /shm_from_mem.txt
unlink ok
[root@rocket ipc]# ./ipc_posix_mmap_unlink /shm_from_mem.txt
unlink shm error = No such file or directory
[root@rocket ipc]# ll /dev/shm/|grep mem
[root@rocket ipc]#

System V shared memory

System call mmap () shared memory by mapping a regular file. System V shared memory is through inter-process communication map file in a special file system shm. That is, each shared memory region corresponding to a special file in the file system shm (which is linked by shmid_kernel structure). The need to share data between processes is placed in IPC shared memory region called the place, all require access to the shared area of ​​the process should be to map the region to share the address space of this process to go. Shared Memory System V IPC obtain or create a shared memory area, and returns the corresponding identifier by shmget. Kernel in obtaining or guarantee shmget create a shared memory area, initialize the appropriate shared memory area at the same time Note shmid_kernel structure, but also in special shm file system, create and open a file with the same name, and to establish the corresponding file in memory dentry and inode structure, the newly opened file does not belong to any process (any process can access the shared memory area). All of this is done shmget system call.

Each zone has a shared memory control structure struct shmid_kernel, shmid_kernel shared memory region is very important in a data structure that is stored in the bridge, and file system management combine, defined as follows:

struct shmid_kernel /* private to the kernel */
{       
    struct kern_ipc_perm shm_perm;
    struct file* shm_file;
    int id;
    unsigned long shm_nattch;
    unsigned long shm_segsz;
    time_t shm_atim;
    time_t shm_dtim;
    time_t shm_ctim;
    pid_t shm_cprid;
    pid_t shm_lprid;
};

The most important structure in a domain should be shm_file, it stores the addresses will be mapped file. Each shared object memory area corresponding to a specific file in the file system shm, under normal circumstances, a special file system shm file is not used in the read (), write () method to access the like, while taking the shared memory mode after the files mapped into the process address space, it can be used directly access its memory access.
System V shared memory kernel structures
Kernel data structures struct ipc_ids shm_ids by maintaining all shared memory area in the system. Figure above shm_ids.entries ipc_id variable refers to a structure array, and each array has a structure ipc_id kern_ipc_perm point pointer structure. Here should be familiar to the reader, for the system V shared memory region is, kern_ipc_perm host is shmid_kernel structure, shmid_kernel is used to describe a region of shared memory, so that the kernel can control all the system shared region. Meanwhile, in the configuration of a file type shmid_kernel pointer pointing to the file system shm shm_file corresponding files, so that, on the shared memory area in association with the shm file in a file system.

After creating a shared memory region, it should be mapped into the process address space, system calls to complete this function shmat (). Because when you call shmget (), have created a file with the same name as the file system shm shared memory area in the corresponding, therefore, call shmat () is equivalent to the process of mapping file the same name as the file system shm in the process, principles and mmap ( ) similar.

System V shared memory usage
#include <sys/ipc.h>
#include <sys/shm.h>

// 获取共享内存区域
int shmget(key_t key, size_t size, int shmflg);

// 连接共享内存区域
void *shmat(int shmid, const void *shmaddr, int shmflg);

// 断开共享内存区域
int shmdt(const void *shmaddr);

// 对共享内存区域进行控制
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

// 将path和proj_id转换成System V IPC key
key_t ftok(const char *pathname, int proj_id);

eg.

Write shared memory

#include <sys/mman.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

typedef struct
{
    char name[32];
    int age;
} people;

int main(int argc, char** argv)
{
    int shm_id,i;
    key_t key;
    people* p_map;
    char temp = 'a';
    
    const char* name = "/dev/shm/my_systemv_shm1";
    key = ftok(name,0);
    if (key == -1)
    {
        perror("ftok error");
        return -1;
    }
    shm_id=shmget(key, 4096, IPC_CREAT);
    if(shm_id == -1)
    {
        perror("shmget error");
        return -1;
    }
    p_map=(people*)shmat(shm_id,NULL,0);
    
    for(int i = 0; i < 10; i++)
    {
        memcpy( ( *(p_map+i) ).name, &temp, 1);
        ( *(p_map+i) ).name[1] = 0;
        ( *(p_map+i) ).age = 20+i;
        temp += 1;
    }
    printf("initialize over\n");
    
    if(shmdt(p_map) == -1)
    {
        perror(" detach error ");
        return -1;
    }
    
    return 0;
}

Reading shared memory

#include <sys/mman.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

typedef struct
{
    char name[32];
    int age;
} people;

int main(int argc, char** argv)
{
    int shm_id,i;
    key_t key;
    people* p_map;
    
    const char* name = "/dev/shm/my_systemv_shm1";
    key = ftok(name,0);
    if (key == -1)
    {
        perror("ftok error");
        return -1;
    }
    shm_id=shmget(key, 4096, IPC_CREAT);
    if(shm_id == -1)
    {
        perror("shmget error");
        return -1;
    }
    p_map=(people*)shmat(shm_id,NULL,0);
    
    for(int i = 0; i < 10; i++)
    {
        printf( "name:%s, ",(*(p_map+i)).name );
        printf( "age %d\n",(*(p_map+i)).age );
    }
    
    if(shmdt(p_map) == -1)
    {
        perror(" detach error ");
        return -1;
    }
    
    return 0;
}

operation result:

[root@rocket ipc]# g++ -g -o ipc_systemv_mmap_writer ipc_systemv_mmap_writer.cpp
[root@rocket ipc]# touch /dev/shm/my_systemv_shm1
[root@rocket ipc]# ./ipc_systemv_mmap_writer
initialize over
[root@rocket ipc]# g++ -g -o ipc_systemv_mmap_reader ipc_systemv_mmap_reader.cpp
[root@rocket ipc]# ./ipc_systemv_mmap_reader
name:a, age 20
name:b, age 21
name:c, age 22
name:d, age 23
name:e, age 24
name:f, age 25
name:g, age 26
name:h, age 27
name:i, age 28
name:j, age 29

观察一下共享内存:
[root@rocket ipc]# ./get_ipc_key /dev/shm/my_systemv_shm1
key = 1084739
[root@rocket ipc]# ipcs
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status     
0x00000000 0          gdm        600        393216     2          dest        
0x00000000 32769      gdm        600        393216     2          dest        
0x00000000 65538      gdm        600        393216     2          dest        
0x00000000 98307      gdm        600        393216     2          dest        
0x00108d43 131076     root       0          4096       0   
 
看到我们新建的共享内存了吧?删除也很简单:
[root@rocket ipc]# ipcrm -m 131076
[root@rocket ipc]# ipcs
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status     
0x00000000 0          gdm        600        393216     2          dest        
0x00000000 32769      gdm        600        393216     2          dest        
0x00000000 65538      gdm        600        393216     2          dest        
0x00000000 98307      gdm        600        393216     2          dest

Guess you like

Origin www.cnblogs.com/joker-wz/p/11006414.html