进程间通信IPC-共享内存(System V)

共享内存

如果要实现两个进程之间进行通信 两个进程之间是不能直接通信的 必须借助内核
如进程1和进程2进行通信的话 进程1可能会借助内核中的某一块内存空间 这块内存空间要是两个进程都能访问的 然后进程1将要通信的内容写入(write 本质上copy)到这块内存空间中去
然后进程2再从这块内存空间中去读取(read 其本质也是copy) 这样就实现了进程间的通信。
问题:
假设我们有三个进程 进程1 进程2 进程3 我们如果假设进程1中某块内存作为进程2 进程3的共享内存 也就是说进程2 和进程3通信其实是通过进程1中的某块内存进程通信的 这种方式是否可行?
不行 因为我们讲进程之间的不能直接访问的 而且另一个问题是 如果进程1死掉了 那么进程2和进程3可能也会跟着出问题。

共享内存的实现方式:

在内核中开辟一块共享内存,其他进程通过“映射”方式获取这段共享内存的引用(指针)

System V共享内存
通过ftok()函数获取System V IPC对象的key —> 通过key创建/打开这个IPC的设施(msg/shm/sem) —>通过System V IPC提供的读/写函数接口交换数据 —>关闭设施

相关函数

ftok用来创建一个System V IPC对象的key

#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);
		
函数功能:ftok用来创建一个System V IPC对象的key 
参数列表: 
						pathname: 一个文件系统中的路径名(必须要存在的并且有权限读取的)
						
						proj_id: 就是一个整数 这个参数存在的意思在于在一个文件也能生成多个IPC key键值。 
								 
								 ftok利用同一个文件最多可得到IPC key键值256个  
								 因为ftok只取proj_id值二进制后8位 及16进制后2位 与文件信息合成IPC key键值
		
								 也就是ftok("/home/china",257)==ftok("/home/china",1) 生成的键值是一样的
		
		
				返回值: 
						成功生成一个唯一的System V IPC对象的key(类型key_t --->int)
						失败返回-1 同时errno被设置 

shmget 创建/打开一个System V的共享内存

#include <sys/ipc.h>
#include <sys/shm.h>

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

					函数功能:创建/打开一个System V的共享内存 
					
					
					参数列表: 
								
								key :System V  IPC对象的key  一般由ftok的返回值获得 
								
								size:以字节为单位指定共享内存区的大小  
									  当实际操作为创建一个新的共享内存区时 必须指定一个不为0的size值(page_size的整数倍:4096)
									  如果实际操作为访问一个已经存在的共享内存去 那么size一般为0  
									  
								shmflg:标志位 
										
										如果是创建共享内存 : IPC_CREAT | 权限位   
										
										如果是打开共享内存 :  0 
										
										其实你完全按照创建的方式指定也可以 因为在创建共享内存的时候 如果发现key对应的共享内存
										已经存在了 那么他会自动忽略后面的选项直接打开
				
					返回值: 
								成功返回创建地共享内存的id (shmid)
								失败返回-1

shmat 映射操作

#include <sys/types.h>
#include <sys/shm.h>

				   void *shmat(int shmid, const void *shmaddr, int shmflg);
				   
				函数功能:将shmid指定的共享内存 映射到进程的地址空间 

								
				参数列表: 
						shmid: 表示你要映射哪块共享内存 (shmget的返回值)
						
						shmaddr: 表示你要映射到进程的地址空间的具体哪个地方 
								 一般为NULL 表示让系统自行分配 
						shmflg: 标志位权限 
								1. SHM_RDONLY 只读 
								2. 0   读写 
								
				返回值:
						成功返回映射空间的首地址(指针)
						失败返回(void *-1 并且errno被设置
int shmdt(const void *shmaddr);

				函数功能:解除映射 
				
				参数列表: 
						shmaddr: 映射空间的首地址  
						
				返回值: 
						成功返回0 
						失败返回-1 并且errno被设置

设置共享内存 比如删除共享内存

#include <sys/ipc.h>
				   #include <sys/shm.h>

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

				函数功能: 对共享内存的一些控制操作 
				
				头文件:如上 
				
				参数列表: 
				
						shmid : 你要对哪块共享内存进行操作 
						
						cmd: 操作命令   不同的命令第三个参数不一样 
							 cmd == IPC_RMID 	删除对应的共享内存 
							 
						buf: 如果cmd == IPC_RMID buf就为NULL 
						
				返回值: 
						成功返回0 
						失败返回-1 并且errno被设置

使用共享内存实现父子进程通信

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
    pid_t pid;
    pid=fork();

    if(pid ==0)
    {
        //创建钥匙
        key_t key=ftok("/home/china",250);
        if(key ==-1)
        {
            perror("key error\n");
            return -1;
        }
        
        //创建共享内存
        int shmid=shmget(key,4096,IPC_CREAT |0666);
        if(shmid ==-1)
        {
            perror("shmid erorr\n");
            return -1;
        }

        //映射
        char * p=shmat(shmid,NULL,0);
        if(p==(char *)-1)
        {
            perror("shmat error\n");
            return -1;
        }

        //写数据
        strcpy(p,"Hello share memory");

        //解映射
        shmdt(p);
    }
    else if(pid >0)
    {
        //创建钥匙
        key_t key=ftok("/home/china",250);
        if(key ==-1)
        {
            perror("key error\n");
            return -1;
        }
        
        
        //创建共享内存
        int shmid=shmget(key,4096,IPC_CREAT |0666);
        if(shmid ==-1)
        {
            perror("shmid erorr\n");
            return -1;
        }

        //映射
        char * p=shmat(shmid,NULL,0);
        if(p==NULL)
        {
            perror("shmat error\n");
            return -1;
        }

        //读数据
        char buf[1024]={0};
        strcpy(buf,p);
        printf("%s\n",buf);

        //解映射
        shmdt(p);
        //删除共享内存
        //shmctl(shmid,IPC_RMID,NULL);
        //wait(NULL);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ChampLixxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值