Linux IPC实践(10) --Posix共享内存

1. 创建/获取一个共享内存

#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);

参数:

name:  共享内存名字;

oflag: 与open函数类型, 可以是O_RDONLY, O_WRONLY, O_RDWR, 还可以按位或上O_CREAT, O_EXCL, O_TRUNC.

mode: 此参数总是需要设置, 如果oflag没有指定O_CREAT, 则mode可以设置为0;

返回值:

成功: 返回一个文件描述符;

失败: 返回-1;

注意-Posix IPC名字限制:

1. 必须以”/”开头, 并且后面不能还有”/”, 形如:/file-name;

2. 名字长度不能超过NAME_MAX

3. 链接时:Link with -lrt.

/** 示例: 共享内存的打开与关闭 **/
int main(int argc,char *argv[])
{
    int shmid = shm_open("/xyz", O_RDWR|O_CREAT, 0666);
    if (shmid == -1)
        err_exit("shmget error");

    cout << "share memory open success" << endl;
    close(shmid);
}

2. 修改共享内存大小

int ftruncate(int fd, off_t length);

该函数不仅可用于修改共享内存大小, 而且可以用于修改文件大小

/** 示例: 修改共享内存大小
将其修改为一个Student结构体的大小
**/
struct Student
{
    char name[32];
    int age;
};
int main(int argc,char *argv[])
{
    int shmid = shm_open("/xyz", O_RDWR|O_CREAT, 0666);
    if (shmid == -1)
        err_exit("shmget error");
    if (ftruncate(shmid, sizeof(Student)) == -1)
        err_exit("ftruncate error");

    cout << "share memory change size success" << endl;
    close(shmid);
}

3. 获取共享内存状态

int fstat(int fd, struct stat *buf);

该函数不仅可用于获取共享内存状态, 而且可以用于获取文件状态, 与前面曾经讲述过的stat, lstat类型;

//stat结构体
struct stat
{
    dev_t     st_dev;     /* ID of device containing file */
    ino_t     st_ino;     /* inode number */
    mode_t    st_mode;    /* protection */
    nlink_t   st_nlink;   /* number of hard links */
    uid_t     st_uid;     /* user ID of owner */
    gid_t     st_gid;     /* group ID of owner */
    dev_t     st_rdev;    /* device ID (if special file) */
    off_t     st_size;    /* total size, in bytes */
    blksize_t st_blksize; /* blocksize for filesystem I/O */
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    time_t    st_atime;   /* time of last access */
    time_t    st_mtime;   /* time of last modification */
    time_t    st_ctime;   /* time of last status change */
};
/** 示例: 获取共享内存的mode和size **/
int main(int argc,char *argv[])
{
    int shmid = shm_open("/xyz", O_RDWR|O_CREAT, 0666);
    if (shmid == -1)
        err_exit("shmget error");
    if (ftruncate(shmid, sizeof(Student)) == -1)
        err_exit("ftruncate error");

    struct stat buf;
    if (fstat(shmid, &buf) == -1)
        err_exit("lstat error");
    // 注意: 获取权限时, 需要&上0777, 而且要以%o, 八进制方式打印
    printf("mode: %o\n", buf.st_mode&0777);
    printf("size: %ld\n", buf.st_size);

    close(shmid);
}

4. 删除一个共享内存对象

int shm_unlink(const char *name);
//示例:
int main(int argc,char *argv[])
{
    shm_unlink("/xyz");
}

5. 共享内存的映射/卸载

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

参数:

addr:  要映射的起始地址, 通常指定为NULL, 让内核自动选择;

length: 映射到进程地址空间的字节数, 通常是先前已经创建的共享内存的大小;

prot: 映射区保护方式(见下);

flags: 标志(通常指定为MAP_SHARED, 用于进程间通信);

fd: 文件描述符(填为shm_open返回的共享内存ID);

offset: 从文件头开始的偏移量(一般填为0);


prot


说明


PROT_READ


页面可读


PROT_WRITE


页面可写


PROC_EXEC


页面可执行


PROC_NONE


页面不可访问


flags


说明


MAP_SHARED


变动是共享的


MAP_PRIVATE


变动是私有的


MAP_FIXED


准确解释addr参数, 如果不指定该参数, 则会以4K大小的内存进行对齐


MAP_ANONYMOUS


建立匿名映射区, 不涉及文件

mmap返回值:

成功: 返回映射到的内存区的起始地址;

失败: 返回MAP_FAILED;

注意:mmap失败返回EACCES错误的原因:

EACCES A file descriptor refers to a non-regular file.

Or MAP_PRIVATE was requested, but fd  is  not  open for reading.

Or MAP_SHARED was requested and PROT_WRITE is set, but fd is not open

in read/write (O_RDWR) mode.  Or PROT_WRITE  is  set,  but  the file is append-only.

/** 示例: 向共享内存写入数据 **/
int main(int argc,char *argv[])
{
    int shmid = shm_open("/xyz", O_RDWR, 0);
    if (shmid == -1)
        err_exit("shm_open error");

    struct stat buf;
    if (fstat(shmid, &buf) == -1)
        err_exit("fstat error");
    Student *p = (Student *)mmap(NULL, buf.st_size,
                                 PROT_WRITE, MAP_SHARED, shmid, 0);
    if (p == MAP_FAILED)
        err_exit("mmap error");
    strcpy(p->name, "Hadoop");
    p->age = 5;

    munmap(p, buf.st_size);
    close(shmid);
}
/** 从共享内存读出数据 **/
int main(int argc,char *argv[])
{
    int shmid = shm_open("/xyz", O_RDONLY, 0);
    if (shmid == -1)
        err_exit("shm_open error");

    struct stat buf;
    if (fstat(shmid, &buf) == -1)
        err_exit("fstat error");
    Student *p = (Student *)mmap(NULL, buf.st_size,
                                 PROT_READ, MAP_SHARED, shmid, 0);
    if (p == MAP_FAILED)
        err_exit("mmap error");

    cout << "name: " << p->name << ", age: " << p->age << endl;

    munmap(p, buf.st_size);
    close(shmid);
}

[附]

-Posix共享内存默认创建在/dev/shm目录下

-可以使用od命令查看共享内存的内容

od -c /dev/shm/xyz

时间: 2024-10-02 22:26:39

Linux IPC实践(10) --Posix共享内存的相关文章

linux网络编程之posix共享内存

今天继续研究posix IPC对象,这次主要是学习一下posix共享内存的使用方法,下面开始: 下面编写程序来创建一个共享内存: 编译运行: 那posix的共享内存存放在哪里呢?上节中学的posix的消息队列是在虚拟文件当中创建一个消息队列,需要我们手工将它挂载到某个目录下才能看到,同样的,posix共享内存也是需要将其挂载,只不过这个挂载操作是由系统完成的,而不用我们人工去操作了,已经挂载到了/dev/shm下了,如下: 接下来要介绍的函数为修改共享内存的大小: [说明]:实际上ftrunca

linux c编程:Posix共享内存区

Posix共享内存区:共享内存是最快的可用IPC形式.它允许多个不相关(无亲缘关系)的进程去访问同一部分逻辑内存.如果需要在两个进程之间传输数据,共享内存将是一种效率极高的解决方案.一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传输就不再涉及内核.这样就可以减少系统调用时间,提高程序效率.共享内存是由IPC为一个进程创建的一个特殊的地址范围,它将出现在进程的地址空间中.其他进程可以把同一段共享内存段“连接到”它们自己的地址空间里去.所有进程都可以访问共享内存中的地址.如果一个进程

Linux IPC实践(7) --Posix消息队列

1. 创建/获取一个消息队列 #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ #include <mqueue.h> mqd_t mq_open(const char *name, int oflag); //专用于打开一个消息队列 mqd_t mq_open(const char *name, int oflag, mode_t mode

细说linux IPC(四):posix 共享内存

上一节讲了由open函数打开一个内存映射文件,再由mmap函数把得到的描述符映射到当前进程地址空间中来.这一节说说另外一种类似的共享内存方法,即 有shm_open函数打开一个Posix.1 IPC名字(也许是文件系统中的一个路径名),所返回的描述符由函数mmap映射到当前进程地址空间.        posix共享内存和尚上一节类似,首先需要制定一个名字参数调用shm_open ,以创建一个新的共享内存对象或打开一个已存在的共享内存对象:然后再调用mmap把共享内存区映射到调用进程的地址空间中

Linux进程IPC浅析[进程间通信SystemV共享内存]

Linux进程IPC浅析[进程间通信SystemV共享内存] 共享内存概念,概述 共享内存的相关函数 共享内存概念,概述: 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到自己的虚拟内存空间,所有用户空间的进程若要操作共享内存,都要将其映射到自己的虚拟内存空间中,通过映射的虚拟内存空间地址去操作共享内存,从而达到进程间的数据通信 共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容 本身不提供同

Linux环境编程之共享内存区(二):Posix共享内存区

现在将共享内存区的概念扩展到将无亲缘关系进程间共享的内存区包括在内.Posix提供了两种在无亲缘关系进程间共享内存区的方法: 1.内存映射文件:由open函数打开,由mmap函数把得到的描述符映射到当前进程地址空间中的一个文件.(上一节就是这种技术) 2.共享内存区对象:由shm_open打开一个Posix名字(也许是在文件系统中的一个路径名),所返回的描述符由mmap函数映射到当前进程的地址空间.(本节内容) Posix共享内存区涉及以下两个步骤要求: 1.指定一个名字参数调用shm_open

linux进程间通信之Posix共享内存用法详解及代码举例

Posix共享内存有两种非亲缘进程间的共享内存方法:1).  使用内存映射文件,由open函数打开,再由mmap函数把返回的文件描述符映射到当前进程空间中的一个文件. 2). 使用共享内存区对象,由shm_open打开一个 Posix IPC名字.再由mmap把返回的描述符映射到当前进程的地址空间. Posix共享内存相关函数头文件及原型:#include <sys/mman.h>int shm_open(const char *name, int oflag, mode_t mode);功能

linux进程间通信之System V共享内存详解及代码示例

共享内存是最快最为高效的进程间通信方式,当共享内存映射到共享它的某个进程的地址空间后,进程间的数据传递就不再牵扯到内核,进程可以直接读取内核,不需要通过内核系统调用进行数据拷贝.一般使用情况,从共享内存中写入或读取数据的进程间需要做同步,例如通过信号量,互斥锁去同步. 共享内存有System V 共享内存和Posix共享内存,本文介绍System V 共享内存.System V共享内存头文件及相关函数原型:#include <sys/shm.h> int shmget(key_t key, s

嵌入式 Linux进程间通信(八)——共享内存

嵌入式 Linux进程间通信(八)--共享内存 一.共享内存 共享内存允许两个或更多进程共享给定的内存区,数据不需要在不同进程间进行复制,是最快的进程间通信方式.使用共享内存唯一需要注意的是多个进程之间对给定存储区的同步访问,但共享内存本身没有提供同步机制,通常使用信号量来实现对共享内存访问的同步. 共享内存编程流程:创建共享内存.映射共享内存.使用共享内存.撤销映射操作.删除共享内存 1.创建共享内存 #include <sys/ipc.h> #include <sys/shm.h&g