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

  • 共享内存:
  • 1、在内核中创建共享内存;
  • 2、进程1和进程2都能够访问到,通过这段内存空间进行数据传递;
  • 3、共享内存是所有进程间通信方式中效率最高不需要在内核中往返进行拷贝
  • 4、共享内存的内存空间大小是4KB的整数倍
  • 常用的接口函数:
  • 一、创建共享内存(shmget函数):
c 复制代码
	#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函数):
c 复制代码
	#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函数):
c 复制代码
	#include <sys/ipc.h>
	#include <sys/shm.h>
	int shmdt(const void *shmaddr);
	/*
	参数:
		    shmaddr:指向共享内存的指针
	返回值:
		    成功 0
		    失败 -1 重置错误码
	*/
  • 四、控制共享内存(shmctl函数):
c 复制代码
	#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 重置错误码
	*/
  • 示例代码:
  • 写端:
c 复制代码
	#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;
	}
  • 读端:
c 复制代码
	#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;
	}
  • 运行结果:
c 复制代码
	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的整数倍分配
相关推荐
好奇龙猫1 小时前
【大学院-筆記試験練習:数据库(データベース問題訓練) と 软件工程(ソフトウェア)(7)】
学习
深圳安锐科技有限公司1 小时前
边坡倾斜自动化监测 倾角仪 如何通过安锐云查看监测曲线?
运维·视觉检测·实时监测·自动化监测·结构健康监测·倾斜角度监测·倾角传感器
济6171 小时前
嵌入式C语言(第二期)
c语言
清木铎1 小时前
leetcode_day4_筑基期_《绝境求生》
算法
清木铎2 小时前
leetcode_day10_筑基期_《绝境求生》
算法
j_jiajia2 小时前
(一)人工智能算法之监督学习——KNN
人工智能·学习·算法
相偎2 小时前
Ubuntu搭建svn服务器
服务器·ubuntu·svn
源代码•宸2 小时前
Golang语法进阶(协程池、反射)
开发语言·经验分享·后端·算法·golang·反射·协程池
2301_783360132 小时前
关于RNAseq——从fastq到gene_counts全流程
笔记·学习
_李小白2 小时前
【AlohaMini学习笔记】第三天:AlohaMini相关技术
笔记·学习