Linux进程通信 -- 共享内存实战
2016-01-27 16:24
537 查看
共享内存原理及实现
system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共享内存区域中,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间中去。这样一个使用共享内存的进程可以将信息写入该空间,而另一个使用共享内存的进程又可以通过简单的内存读操作获取刚才写入的信息,使得两个不同进程之间进行了一次信息交换,从而实现进程间的通信。
共享内存允许一个或多个进程通过同时出现在它们的虚拟地址空间的内存进行通信,而这块虚拟内存的页面被每个共享进程的页表条目所引用,同时并不需要在所有进程的虚拟内存都有相同的地址。
进程对象对于共享内存的访问通过key(键)来控制,同时通过key进行访问权限的检查。
相关函数
shmget函数
功能:用来创建共享内存
函数原型:
#include <sys/shm.h> int shmget(key_t key, size_t size, int shmflag);
参数
key:创建的内存id
szie:内存大小
shmflag:权限标志,类似文件权限mode
返回值:成功返回非负整数key;失败返回-1
shmat函数
功能:将共享内存连接到进程地址空间
函数原型:
void *shmat(int shm_id, const void *shm_addr, int shmflg);
参数
shm_id:共享内存标识
shm_addr:指定连接的地址(一般选择NULL,由内核自动选一个地址)
shmflg:它的两个可能取值是SHM_RND和SHM_RONLY
返回值:成功返回一个指向共享内存的第一个字节的指针;失败返回-1
shmctl函数
功能:控制及操作共享内存
函数原型:
int shmctl(int shm_id, int command, struct shmid_ds *buf);
参数
第一个参数
shm_id是
shmget返回的共享内存标识符。
第二个参数
command是要采取的动作,它可以取三个值,具体请见终端
man shmctl。
第三个参数
shmid_ds至少包含如下成员:
struct shmid_ds { uid_t shm_perm.uid; uid_t shm_perm.gid; mode_t shm_perm.mode; };
shmdt函数
功能:用于将共享内存段与进程空间分离。
int shmdt(const void *shmaddr);
参数
shmaddr通常为
shmat的成功返回值。
返回值:成功返回0,失败时返回-1.
注意,将共享内存分离并没删除它,只是使得该共享内存对当前进程不在可用。
相关命令
查看共享内存ipcs -m
删除共享内存
ipcrm -m shmid
父子进程使用共享内存通信的实现
//1.c #include <stdio.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> int main(int argc, char *argv[]) { key_t key = ftok(".",1); int shmid = shmget(key, 1024, 0666 | IPC_CREAT); if(shmid == -1) { perror("create sm error\n"); exit(1); } if(fork() > 0) //父进程操作 { char *p = (char*)shmat(shmid, NULL, 0); //将共享内存连接到进程地址空间 memset(p, '\0', 1024); //将地址字符串数据置为空 strncpy(p, " hey guys how are you here", 1024);//写入数据 printf("parent_pid = %d send data: %s\n", getpid(),p); sleep(2); wait(NULL); //防止僵尸进程 if(shmctl(shmid, IPC_RMID,0) == -1) //删除共享内存 { perror("shmctl"); exit(-1); } exit(0); } else //子进程操作 { sleep(5); //给父进程写数据的时间 char *sp = (char*)shmat(shmid, NULL, 0);//将共享内存连接到进程地址空间 printf("son_pid = %d, shmid = %d read data: %s\n", getpid(), shmid, sp); exit(0); } }
执行操作
yu@ubuntu:~/0126/gxnc$ gcc -o run 1.c yu@ubuntu:~/0126/gxnc$ ./run parent_pid = 7428 send data: hey guys how are you here son_pid = 7429, shmid = 2752523 read data: hey guys how are you here
非亲缘关系两进程通信–使用共享内存案例
1、write.c//1、write.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> int main() { key_t key = ftok(".", 1);//以当前目录文件创建key if(key == -1) { perror("ftok"); exit(-1); } int shmid = shmget(key, 4096, 0666 | IPC_CREAT);//创建共享内存,大小4096,权限0666 if(shmid == -1) { perror("shmget"); exit(-1); } char *pMap = (char*)shmat(shmid, NULL, 0); //将共享内存连接到进程地址空间 memset(pMap, '\0', 4096);//置为空 memcpy(pMap, "nihaoma guys", 4096);//写数据 if(shmdt(pMap) == -1) { perror("shmdt"); exit(-1); } }
执行操作
yu@ubuntu:~/0126/gxnc/feiqin$ gcc -o write write.c yu@ubuntu:~/0126/gxnc/feiqin$ ./write
此时查看共享内存发现有一条刚创建的共享内存记录:
yu@ubuntu:~/0126/gxnc/feiqin$ ipcs -m ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x010197bd 2818059 yu 666 4096 0
2、read.c
//2、read.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> int main() { key_t key = ftok(".", 1); //获取当前目录的key if(key == -1) { perror("ftok"); exit(-1); } int shmid = shmget(key, 4096, IPC_CREAT); //shmid赋值 if(shmid == -1) { perror("shmid == -1"); exit(-1); } char *p = (char*)shmat(shmid, NULL, 0);//将共享内存连接到进程地址空间 printf("receive the data: %s\n", p); if((ret = shmctl(shmid, IPC_RMID, 0)) == -1)//删除共享内存 { perror("shmctl"); exit(-1); } }
执行操作
yu@ubuntu:~/0126/gxnc/feiqin$ ./read receive the data: nihaoma guys yu@ubuntu:~/0126/gxnc/feiqin$ ipcs -m ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status
此时已经删除创建的共享内存,清理完毕
相关文章推荐
- linux实践-弱密码导致服务器被黑
- VMware建立一个裸机linux
- Linux Centos 6.6安装Mysql
- linux与windows之间传输文件工具rz上传大文件失败问题解决方案
- linux下ssh上传下载文件到服务器
- linux kernel 从入口到start_kernel 的代码分析
- linux下安装软件后的环境变量设置
- 20160127 linux 学习笔记
- Kali_linux系统SSH参数配置
- Linux netstat命令参数解释
- Linux启动网卡时出现RTNETLINK answers File exists错误解决方法
- 正确配置Linux系统ulimit/nproc值的方法
- Linux 用户打开进程数的调整
- linux学习笔记一----------文件相关操作
- linux 后台运行方法
- Linux指令之--tail && cat
- linux之唤醒流程
- 1-Linux-系统目录
- linux之待机流程
- 3-Linux-档案属性-chmod-chown-chgrp