多进程间通信学习之共享内存

  • 共享内存:
  • 1、在内核中创建共享内存;
  • 2、进程1和进程2都能够访问到,通过这段内存空间进行数据传递;
  • 3、共享内存是所有进程间通信方式中效率最高不需要在内核中往返进行拷贝
  • 4、共享内存的内存空间大小是4KB的整数倍
  • 常用的接口函数:
  • 一、创建共享内存(shmget函数):
	#include <sys/ipc.h>
	#include <sys/shm.h>
	int shmget(key_t key, size_t size, int shmflg);
	/*
	参数:
		    key:键值
		        key 通过ftok获取
		        IPC_PRIVATE:只能用于亲缘进程间的通信
		    size:共享内存的大小  PAGE_SIZE(4k)的整数倍
		    shmflg:共享的标志位
		        IPC_CREAT|0666 或 IPC_CREAT|IPC_EXCL|0666
	返回值:
		    成功 共享内存编号
		    失败 -1 重置错误码
	*/
  • 二、映射共享内存到当前的进程空间(shmat函数):
	#include <sys/ipc.h>
	#include <sys/shm.h>
	void *shmat(int shmid, const void *shmaddr, int shmflg);
	/*
	参数:
		    shmid:共享内存编号
		    shmaddr:NULL,让系统自动分配
		    shmflg:共享内存操作方式
		        0    		  读写
		        SHM_RDONLY    只读
	返回值:
		    成功 指向共享内存的地址
		    失败 (void *)-1 重置错误码
	*/
  • 三、取消地址映射(shmdt函数):
	#include <sys/ipc.h>
	#include <sys/shm.h>
	int shmdt(const void *shmaddr);
	/*
	参数:
		    shmaddr:指向共享内存的指针
	返回值:
		    成功 0
		    失败 -1 重置错误码
	*/
  • 四、控制共享内存(shmctl函数):
	#include <sys/ipc.h>
	#include <sys/shm.h>
	int shmctl(int shmid, int cmd, struct shmid_ds *buf);
	/*
	参数:
		    shmid:共享内存编号
		    cmd:操作的命令码
		        IPC_STAT:获取
		        IPC_SET:设置
		        IPC_RMID:删除共享内存
		            标记要销毁的段。实际上,只有在最后一个进程将其分离之后 
		            (关联结构shmid_ds的shm_nattch成员为零时), 
		            段才会被销毁。
		            调用者必须是段的所有者或创建者,或具有特权。buf参数被忽略。
		    buf:共享内存属性结构体指针
	返回值:
			成功 0
			失败 -1 重置错误码
	*/
  • 示例代码:
  • 写端:
	#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>
	
	#include <sys/types.h>
	#include <sys/ipc.h>
	
	#include <sys/shm.h>
	#include <unistd.h>
	
	#define PIGE_SIZE 4*1024
	
	int main(int argc, char const *argv[])
	{
	    //获取键值
	    key_t key = ftok("/home/linux/work/MSG", 'k');
	    if(-1 == key)
	    {
	        perror("ftok error");
	        exit(1);
	    }
	    //创建共享内存
	    int shmid = shmget(key, 2*PIGE_SIZE,IPC_CREAT|0666);
	    if(-1 == shmid)\
	    {
	        perror("shmget error");
	        exit(1);
	    }
	    //映射共享内存
	    char *sh_addr = (char *)shmat(shmid, NULL, 0);
	    if((void *) -1 == sh_addr)
	    {
	        perror("shmat error");
	        exit(1);
	    }
	    //向共享内存中写入数据
	    while(1)
	    {
	        fgets(sh_addr,128,stdin);
	        sh_addr[strlen(sh_addr)-1] = '\0';
	        if(!strncmp(sh_addr,"quit",4))
	        {
	            break;
	        }
	    }
	    //取消映射
	    if(-1 == shmdt(sh_addr))
	    {
	        perror("shmdt error");
	        exit(1);
	    }
	    //删除共享内存
	    if(-1 == shmctl(shmid, IPC_RMID, NULL))
	    {
	        perror("shmctl error");
	        exit(1);
	    }
	    
	    return 0;
	}

  • 读端:
	#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>
	
	#include <sys/types.h>
	#include <sys/ipc.h>
	
	#include <sys/shm.h>
	#include <unistd.h>
	
	#define PIGE_SIZE 4*1024
	
	int main(int argc, char const *argv[])
	{
	    //获取键值
	    key_t key = ftok("/home/linux/work/MSG", 'k');
	    if(-1 == key)
	    {
	        perror("ftok error");
	        exit(1);
	    }
	    //创建共享内存
	    int shmid = shmget(key, 2*PIGE_SIZE,IPC_CREAT|0666);
	    if(-1 == shmid)\
	    {
	        perror("shmget error");
	        exit(1);
	    }
	    //映射共享内存
	    char *sh_addr = (char *)shmat(shmid, NULL, 0);
	    if((void *) -1 == sh_addr)
	    {
	        perror("shmat error");
	        exit(1);
	    }
	    while(1)
	    {
	        sleep(2);//防止刷屏
	        printf("%s\n",sh_addr);
	        if(!strncmp(sh_addr,"quit",4))
	        {
	            break;
	        }
	    }
	    //取消映射
	    if(-1 == shmdt(sh_addr))
	    {
	        perror("shmdt error");
	        exit(1);
	    }
	    //删除共享内存
	    if(-1 == shmctl(shmid, IPC_RMID, NULL))
	    {
	        perror("shmctl error");
	        exit(1);
	    }
	    return 0;
	}

  • 运行结果:
	linux@ubuntu:~/work/MSG$ gcc w3.c -o w3
	linux@ubuntu:~/work/MSG$ ./w3
	hi
	hello
	china
	quit
	linux@ubuntu:~/work/MSG$ gcc r3.c -o r3
	linux@ubuntu:~/work/MSG$ ./r3
	hi
	hi
	hi
	hello
	china
	china
	china
	quit
	shmctl error: Invalid argument
  • 注意:
  • 不按4k的整数倍给shmget传参,分配时也是按4k的整数倍分配
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值