跟着iMX28x开发套件学linux-08

Posted diskiii

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跟着iMX28x开发套件学linux-08相关的知识,希望对你有一定的参考价值。

八、linux应用编程之六:共享内存

共享内存是进程间通信的一种方法。共享内存实际上是两个进程打开同一段内存,并都映射到进程地址中,这样就类似于malloc了一个内存*ptr,进程A往这个地址中写数据,进程B就可以从这个地址读取到进程A写进去的数据。

使用共享内存有以下步骤:

shm_open():打开或创建一个共享内存。

ftruncate():设置共享内存的大小。

mmap():将共享内存映射到当前进程的地址空间。

*ptr:写入或读取共享内存中的数据。

munmap():取消共享内存在当前进程的映射,为删除共享内存做准备。

shm_unlink():删除共享内存。

 

函数详细说明

 

1) 函数原型:int shm_open(const char *name, int oflag, mode_t mode);

输入参数:name,共享内存名; oflag,打开标志位; mode,设置共享内存的权限。

值:int,成功返回共享内存的文件描述符,失败返回-1

   例:fd = shm_open(SHAMNAME,O_CREAT|O_TRUNC|O_RDWR,S_IRUSR|S_IWUSR);

 

2) 函数原型:int ftruncate(int fd, off_t length);

输入参数:fd,共享内存的文件描述符;length,要设置的大小。

值:int,成功返回0,失败返回-1

   例:ftruncate(fd, SHMSIZE);

 

3) 函数原型:void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

输入参数:addr,要映射到的内存地址,可以为NULLlength,要映射的大小;prot,对映射存 储区的保护要求;flags,映射标志位;fd,要映射的共享内存的文件描述符;offset, 要映射的字节在共享内存中的偏移量。

值:void*,无类型指针,与malloc()的返回值类似。若映射失败返回MAP_FAILED

   例:ptr = mmap(NULL, SHMSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

 

4) 函数原型:int munmap(void *addr, size_t length);

输入参数:*addr,共享内存在进程中映射的地址;length,映射的字节数。

值:int,成功返回0,否则返回1

   例:munmap(ptr, SHMSIZE);

 

5) 函数原型:int shm_unlink(const char *name);

输入参数:*name,共享内存名;

值:成功返回0,失败返回1

   例:shm_unlink(SHMNAME);

 

参数可能取值:

shm_open()

mmap()

oflag

O_RDONLY:共享内存以只读方式打开

prot

PROT_READ:映射区可读

O_RDWR:共享内存以可读写方式打开

PROT_WRITE:映射区可写

O_CREAT:共享内存不存在才创建

PROT_EXEC:映射区可执行

O_EXCL:如果指定了 O_CREAT,但共享内存已经存在时返回错误

PROT_NONE:映射区不可访问

O_TRUNC:如果共享内存已经存在则将其大小设置为 0

flag

MAP_FIXED:返回值必须等于 addr。因为这不利于移植性,所以不鼓励使用此标志

mode

S_IRWXU:所属用户读、写和执行权限

MAP_SHARED:多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化

S_IRUSR :所属用户读权限

MAP_PRIVATE:多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化

S_IWUSR:所属用户写权限

S_I W/R USR/GRP/OTHmode的格式

 

 

示例代码

进程A代码:

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

#define SHMSIZE 10
#define SHMNAME "shmtest"

int main(){
    int fd;
    char *ptr;
    
    fd = shm_open(SHMNAME, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR);
    if(fd < 0){
        fprintf(stderr, "open shm error\\n");
        exit(-1);
    }
    
    ftruncate(fd, SHMSIZE);
    
    ptr = mmap(NULL, SHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if(ptr == MAP_FAILED){
        perror("mmap error\\n");
        exit(-1);
    }
    
    *ptr = 18;
    
    munmap(ptr, SHMSIZE);
    
    shm_unlink(SHMNAME);
    
    return 0;
    
}

 

进程B代码:

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

#define SHMSIZE 10
#define SHMNAME "shmtest"

int main(){
    int fd;
    char* ptr = NULL;
    
    fd = shm_open(SHMNAME, O_RDWR|O_CREAT, S_IWUSR|S_IRUSR);
    if(fd <0){
        perror("open shm error\\n");
        exit(-1);
    }
    
    ftruncate(fd, SHMSIZE);
    
    ptr = mmap(NULL, SHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if(ptr<0){
        perror("map shm error\\n");
        exit(-1);
    }
    
    while(*ptr != 18){
        sleep(1);
    }
    
    printf("ptr : %d\\n", *ptr);
    
    munmap(ptr, SHMSIZE);
    shm_unlink(SHMNAME);
    
    return 0;

}

 

运行结果,先后台运行进程B,再运行进程A

 

进程B用函数shm_open()创建了名为shmtest的共享内存,然后调用ftruncate()函数对共享内存设置大小,接着调用mmap()函数,将共享内存映射到进程B的地址空间中,while死循环检查共享内存的值是否为18

接着运行进程A,用shm_open()函数打开进程B创建的shmtest共享内存,然后设置大小,映射到进程A的地址空间中,接着写入18

进程B接收到进程A写入的18后,输出信息到屏幕,然后终止进程。

 

 

PS:需要注意的是,使用了共享内存的程序在编译链接的时候要加上-lrt选项,否则提示shm_open()没有定义。

 

 

以上是关于跟着iMX28x开发套件学linux-08的主要内容,如果未能解决你的问题,请参考以下文章

IMX6开发板qt creator直接编译ARM架构程序

PCIe:lspci 显示“内存在 <未分配> ...”

#盲盒+码##跟着小白一起学鸿蒙#如何编译OpenHarmony自带APP

#跟着小白一起学鸿蒙# [番外]一起学做FlappyBird

跟着老杜学MyBatis+第2天+MyBatis入门程序

跟着老杜学MyBatis+第2天+MyBatis入门程序