Linux系统编程之进程间通信(共享内存)

前言:首先说一下共享内存实现进程间通信的基本原理,共享内存实际是操作系统在实际物理内存中开辟的一段内存。
共享内存实现进程间通信,是操作系统在实际物理内存开辟一块空间,一个进程在自己的页表中,将该空间和进程地址空间上的共享区的一块地址空间形成映射关系。另外一进程在页表上,将同一块物理空间和该进程地址空间上的共享区的一块地址空间形成映射关系。
在这里插入图片描述
看上图,一个进程往该共享内存空间写入内容时,另一个进程也可以访问到这个共享内存空间,读取到一个进程写入的内容,相反也可,这就实现了两个进程间的通信。要实现进程间通信需要两个进程能够看到同一块空间,系统开辟的共享内存就是两进程看到的同一资源。

注意:共享内存可以实现两个不相关的进程间的通信,而且共享内存是进程间通信方式中最快的。

一、共享内存相关的API
1.shmget函数
函数原型:

int shmget(key_t key, size_t size, int shmflg);

作用:创建一个共享内存空间

参数:
key:为共享内存的名字,一般由ftok函数创建
size:共享内存的大小,以page为单位,大小为4096的整数倍。
shmflg:权限标志,常用两个IPC_CREATIPC_EXCL,一般后面还加一个权限,相当于文件的权限。

                            IPC_CREAT:创建一个共享内存返回,已存在打开返回
                            IPC_EXCL:配合着IPC_CREAT使用,共享内存已存在出错返回。
                            使用:IPC_CREAT | IPC_EXCL | 0666

返回值:成功返回一个非负整数,即共享内存的标识码,失败返回-1

来到这里顺便提一下,为什么有了标识码了,还要有key呢?
因为key是内核级别的,供内核标识,shmget返回值是用户级别的,供用户使用的。

ftok函数:
函数原型:

 key_t ftok(const char *pathname, int proj_id);

作用:返回一个key

参数:
pathname:pathname就是你指定的文件名(路径),要求文件必须存在,一般使用当前目录
proj_id:至少8位的项目id,不能为0,两参数可以是任意值,但是要符合格式

返回值:成功返回key的值,失败返回-1,如果失败的话,再重新填写参数即可

2.shmat函数
函数原型:

void *shmat(int shmid, const void *shmaddr, int shmflg);

作用:使创建的共享内存与调用该函数进程的进程地址空间产生关联

参数:
shmid:共享内存的标识,shmget的返回值
shmaddr:指定进程地址空间连接的地址。如果设置为null,默认让系统定要关联的地址
shmflg:权限,常见有两个SHM_RDONLY(只读)和SHM_REMAP(重新映射一个进程地址空间没这样shmaddr不能为空)。设为0,系统默认

返回值: 返回映射到进程地址空间共享区的开始地址

3.shmdt函数
函数原型:

int shmdt(const void *shmaddr);

作用:删除共享内存与进程地址空间的映射关系,将页表映射关系删除,释放进程地址空间,与free有点相似

参数:
shmaddr:共享内存映射到进程地址空间的地址,shmat的返回值

注意:shmat要与shmdt一起使用才起作用

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

4.shmctl函数
函数原型

  int shmctl(int shmid, int cmd, struct shmid_ds *buf);

作用:用于控制共享内存

参数:
shmid:共享内存的标识,即(shmget的返回值)
cmd:以什么方式来控制共享内存,常用IPC_RMID来释放共享内存
buf:指向一个共享内存的数据结构,struct shmid_ds

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

二、直接上demo
稍微提示一下:
共享内存的步骤;
1.创建/获取共享内存
2.共享内存关联进程
3.删除共享内存与进程的关联
4.释放共享内存

shmwdemo10.c

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.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);

int main()
{
    
    
        key_t key;
        int shmid;
        char *shmaddr;

        key = ftok(".",123);

        shmid = shmget(key,1024*5,IPC_CREAT|0666);  //get the id

        if(shmid == -1)
        {
    
    
                printf("Sorry fail to creat the share ram!\n");
                exit(-1);
        }
        shmaddr = shmat(shmid,0,0);   //point to memory space
        printf("shmat ok!\n");

        strcpy(shmaddr,"hello welcome to receive the message!"); //Input data to the space
        sleep(6);
        shmdt(shmaddr);          //free the space
        shmctl(shmid,IPC_RMID,0);//delete the id

        printf("ok creat share ram success,quit!\n");
        return 0;
}

shmrdemo11.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.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 main()
{
    
    
        key_t key;
        int shmid;
        char *shmaddr;

        key = ftok(".",123);
        if(key == -1)
        {
    
    
                printf("Sorry fail to get the key!\n");
        }

        shmid = shmget(key,1024*5,0);
        if(shmid == -1)
        {
    
    
                printf("Sorry fail to get the share ram!\n");
                exit(-1);
        }
        
        shmaddr = shmat(shmid,0,0);
        printf("shmat ok!\n");
        printf("the shmaddr is :%s\n",shmaddr);

        shmdt(shmaddr);
        return 0;
}

结果:
写端的结果:
在这里插入图片描述
读端结果:
在这里插入图片描述
写端在创建完共享内存并向内存写进东西的时候,在写端的代码里可以看出,写端等待读端5s,让读端去把内容读取出来。

共享内存优秀博文参考

学习笔记,仅供参考

猜你喜欢

转载自blog.csdn.net/weixin_51976284/article/details/124734495