共享内存总结

来源:互联网 发布:我朝太祖知乎 编辑:程序博客网 时间:2024/06/03 19:16

Posix共享内存涉及以下两个步骤:

    1、指定一个名字参数调用shm_open,以创建以一个新的共享内存区对象或打开一个已存在的共享内存区对象。

    2、调用mmap把这个共享内存区映射到调用进程的地址空间。

    头文件:

    #include<sys/mman.h>

    #include<sys/stat.h>

    #include<fcntl.h>

    int shm_open(const char *name, int oflag, mode_t mode);

    int shm_unlink(const char *name);

    Link with -lrt(要注意连接这个库)

    oflag参数是O_CRTEA|O_RDWR等标志;

    mode参数指定权限位如果没有指定O_CREAT标志,那么该参数可以指定为0。(如果是创建的话权限要给够,平常是0644的权限,否则别的进程可能没有权限)。

    一般创建的文件是自动放在/dev/shm/的目录下的。

    新创建的文件大小一般为0,所以mmap函数调用文件标识符的时候会出错,这时候要用ftruncate()函数扩大文件

    #include<unistd.h>

    int ftruncate(int fd,off_t length);    成功返回0,出错返回-1

    对于一个普通文件:如果该文件的大小大于length参数,额外的数据就会被丢掉。

    对于一个共享内存区对象:把该对象的大小设置成length字节。

    当打开一个已存在的共享内存对象时,我们可以调用fstat来获取有关该对象的信息。    

    #include<sys/types.h>

    #include<sys/stat.h> 

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

    stat结构有12个或以上的成员,  但当fd指代一个共享内存区对象时,只有四个成员含有信息。

    struct stat{

        mode_t    st_mode;

        uid_t        st_uid;

        gid_t        st_gid;

        off_t        st_size;            

    };

调用时不用定义这个结构体,直接实例化就行了,如:struct stat sta;

下面例子为一个往共享内存里写入内容,另一个读取。

读取端:

#include<stdio.h>

#include<unistd.h>

#include<sys/mman.h>

#include<fcntl.h>

#include<string.h>

#include<sys/stat.h>

 

int main(int argc,char* argv[])

{

    int fd = shm_open(argv[1],O_RDONLY,0);

    void* buf = NULL;

    if((buf = mmap(NULL,BUFSIZ,PROT_READ,MAP_SHARED,fd,0)) ==MAP_FAILED ){

        perror("mmap error\n");

        return 1;

    }

    sleep(1);

    while(1){

        printf("read:%s\n",buf);

        sleep(3);

    }

    munmap(buf,BUFSIZ);

    close(fd);

}

写入端:

 

int main(int argc,char* argv[])

{

    int fd = shm_open(argv[1],O_CREAT|O_RDWR,0644);

    if(fd == -1){

        perror("shm_open error\n");

        return 1;

    }

    ftruncate(fd,100);

    void* buf = NULL;

    if((buf = mmap(NULL,BUFSIZ,PROT_WRITE,MAP_SHARED,fd,0))== MAP_FAILED){

        perror("mmap error\n");

        return 1;

    }

    int i;

    for(i=2;i<argc;i++){

        strcpy(buf,argv[i]);

        sleep(3);

    }

    munmap(buf,BUFSIZ);

    close(fd);

}

 

 

System v共享内存

#include<sys/shm.h>

    int shmget(key_t key,size_t size,int oflag);    返回:成功则为共享内存区对象,出错为-1

    key 的值可以是ftok的返回值,也可以是IPC_PRIVATE.

    ftok()               是非亲缘进程间

    IPC_PRIVATE         是亲缘进程间的

     size以字节为单位指定内存区的大小。当实际操作为创建一个新的共享内存区时,必须指定一个不为0的size值。如果实际操作为访问一个已存在的共享内存区,那么size应为0.

     oflag是读写权限值的集合,还可以是IPC_CREAT或IPC_CREAT|IPC_EXCL

     void *shmat(int shmid, const void*shmaddr, int flag); 返回:成功为映射区的起始地址,出错为-1

     shmid是shmget返回的标识符。

  如果shmaddr是一个空指针,那么系统替调用者选择地址。这是推荐的方法。

  如果shmaddr是一个非空指针,那么返回地址取决于调用者是否给flag参数指定了SHM_RND值:

     如果没有指定SHM_RND,那么相应的共享内存区附接到由shmaddr参数指定的地址;

     如果指定了SHM_RND,那么相应的共享内存区附接到由shmaddr参数指定的地址向下舍入一个SHMLBA常值。LBA代表“底端边界地址”。

     int shmdt(const void* shmaddr);    返回:成功为0,出错为-1

     当一个进程终止时,他当前附接着的所有共享内存区都自动断接掉。本函数调用并不是删除所指定的共享内存区。

     int shmctl(int shmid,int cmd, struct shmid_ds* buff);    返回:成功为0,错误为-1

cmd有三个命令:

1、IPC_RMID     从系统中删除由shmid标识的共享内存区并拆除它。

2、  IPC_SET     给所指定的共享内存区设置其shmid_ds结构的以下三个成员:shm_perm.uid、shm_perm.gid和shm_perm.mode,它们的值来自buff参数指向的结构中的相应成员。shm_ctime的值也用当前时间替换。

3、IPC_STAT (通过buff参数)向调用者返回所指定共享内存区当前的shmid_ds结构。

例子:下面例子为一个往共享内存里写入内容,另一个读取。

写入:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <fcntl.h>

#include <sys/shm.h>

 

int main(int argc,char* argv[]){

key_t key = ftok(argv[1],1);

if(-1 == key){

perror("ftok err");

return 1;

}

int shmid = shmget(key,0,O_RDWR);

if(-1 == shmid){

perror("shmget err");

return 1;

}

void* buf = shmat(shmid,NULL,0);

if((void*)-1 == buf){

perror("shmat err");

return 1;

}

strcpy(buf,"hello shmat\n");

shmdt(0);

return 0;

}

读取:

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <sys/shm.h>

 

int main(int argc,char* argv[]){

key_t key = ftok(argv[1],1);

if(-1 == key){

perror("ftok err");

return 1;

}

int shmid = shmget(key,0,O_RDONLY);

if(-1 == shmid){

perror("shmget err");

return 1;

}

void* buf = shmat(shmid,NULL,SHM_RDONLY);

printf("%s\n",buf);

shmdt(NULL);

printf("shmid:%d\n",shmid);

return 0;

}

 

 

原创粉丝点击