共享内存2
2013-05-18 17:19
141 查看
说明:只供学习交流,转载请注明出处
五,shmat函数
shmat函数与shmdt函数用于实现对共享内存的操作。shmat函数用于将共享内存连接到指定的进程地址空间中。当共享内存连接到指定地址空间后,进程将获得指向该内存段的指针,然后可以根据指针实现对共享内存段的访问。完成对共享内存段的操作后,需要调用shmdt函数将共享内存段从进程的地址空间分离。
shmat函数的具体信息如下表所示:
shmat函数
头文件 | #include <sys/types.h> #include <sys/shm.h> | ||
函数原型 | void *shmat(int shmid, const void *shmaddr, int shmflg); | ||
返回值 | 成功 | 失败 | 是否设置errno |
共享内存的连接地址 | -1 | 是 |
(1):shmaddr为NULL时,系统自动选择合适内存地址,用于连接进程地址空间和共享内存段。
(2):shmaddr不为NULL,且shmflg中指定了SHM_RND,则将共享内存连接到(shmaddr-(add
mod SHMLBA))所示的地址。SHM_RND的意思为取整,SHMLBA表示低边界地址的整数倍。
错误信息:
EACCES:调用进程没有在cmd参数中指定连接类型的权限。
EINVAL:非法的shmid参数、非法的shmaddr地址、指定了SHM_REMAP或参数shmaddr为空。
ENOMEM:无法为描述符或分页表分配内存。
六,shmdt函数
Shmdt函数用于分离连接到进程地址空间的共享内存段,该函数的具体信息如下表:
shmdt函数
头文件 | #include <sys/types.h> #include <sys/shm.h> | ||
函数原形 | int shmdt(const void *shmaddr); | ||
返回值 | 成功 | 失败 | 是否设置errno |
0 | -1 | 是 |
错误信息:
EINVAL:shmaddr参数指定的内存地址没有共享内存与之相连。
实例:
程序使用shmat函数和shmdt函数来实现通过共享内存进程进程间数据交换。程序首先创建一共享内存段,并在其中写入数据。然后调用fork函数来产生子进程,在子进程中读共享内存中的数据,并进行修改。父进程等待子进程执行完成后,输出共享内存段中的数据。
如果不使用共享内存,父子进程都运行在各自的虚拟地址空间中。因此,不可能出现修改子进程中内存数据时,父进程中发生对应改变的现象。这充分说明了使用共享内存可以实现进程间的数据交换。
具体代码如下:
//使用共享内存实现进程间的通信 #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <string.h> #include <stdlib.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <sys/wait.h> //进程数据段、代码段的地址,为了说明共享内存段所处的位置 extern int etext, edata, end; int main(int argc, char *argv[]) { int shmid; int proj_id; key_t key; int shm_size; char *shm_addr = NULL; char *addr = NULL; pid_t pid; //检测输入参数是否符合要求 if ( argc != 3 ) { printf("Usage: %s shared_memory_size info\n", argv[0]); return (1); } shm_size = atoi(argv[1]); //产生IPC关键字 proj_id = 2; key = ftok("./program", proj_id); if ( key == -1 ) { perror("Cannot generate the IPC key"); return (1); } //创建共享内存,大小为输入的给定值 shmid = shmget(key, shm_size, IPC_CREAT|0660); if (shmid == -1) { perror("Cannot create a shared memory segment"); return (1); } //将共享内存与进程地址空间相连接 addr = (char *)shmat(shmid, NULL, 0); shm_addr = addr; if (shm_addr == (char*)-1) { perror("Cannot attach the shared memory to process"); return (1); } //给出进程地址信息,以确认共享内存位于进程地址空间 printf("======address information======\n"); printf("etext address: %x\n",(unsigned int) &etext); printf("edata address: %x\n", (unsigned int)&edata); printf("end address: %x\n", (unsigned int)&end); printf("shared memory segment address: %x\n",(unsigned int)shm_addr); printf("===============================\n"); //将输入的信息复制到共享内存段中 strcpy(shm_addr, argv[2]); printf("The input string is : %s\n", argv[2]); printf("Before fork, in shared memory segment the string is : %s\n", shm_addr); //调用fork创建子进程,并在子进程中修改共享内存中的数据 //父进程等待子进程结束后,输出共享内存中的数据 pid = fork(); if (pid == -1) { perror("Cannot create new process"); return (1); } else if(pid == 0) { printf("In child process, the string is %s\n", shm_addr); printf("Modify the content in shared memory\n"); *shm_addr += 1; _exit(0); } else { wait(NULL); printf("after fork, int shared memory segment the string is %s\n", shm_addr); if (shmdt(shm_addr) == -1) { perror("Cannot release the memory"); return (1); } //删除共享内存段 if (shmctl(shmid, IPC_RMID, NULL) == -1) { perror("Cannot delete existing memory segment"); return (1); } } shm_addr = NULL; addr = NULL; printf("Down!\n"); return (0); } 运行结果: [root@localhost test]# ./sharememory 1024 "hello word" ======address information====== etext address: 8048974 edata address: 8049d24 end address: 8049d2c shared memory segment address: b7fe0000 =============================== The input string is : hello word Before fork, in shared memory segment the string is : hello word In child process, the string is hello word Modify the content in shared memory after fork, int shared memory segment the string is iello word Down! [root@localhost test]#
说明:由于不存在多线程同时访问的问题,不存在保护共享内存段的问题。当存在多线程同时对共享内存进行访问时,必须使用信号量来进行进程间互斥。
相关文章推荐
- Unix IPC之基于共享内存的计数器
- ipcs 命令 分析消息队列、共享内存和信号量
- 理论+实践来认识/dev/shm(共享内存目录)
- 进程间通信之:共享内存
- Linux 进程通信之 共享内存
- Linux环境进程间通信: 共享内存(上)
- 《老罗的Android之旅》阅读笔记——匿名共享内存
- 进程间通信的几种方式:管道、信号、消息队列、共享内存
- Linux环境进程间通信(五): 共享内存
- 共享内存
- C++11线程指南(6)--共享内存与互斥
- linux 下查看共享内存的使用以及删除共享内存
- IPC_共享内存
- Redis深入之内存回收和对象共享
- SAP内存/ABAP内存/共享内存区别(收集来的)
- android中application共享数据以及内存泄露问题
- 父子进程共享内存通信的三种方法
- unpv2-共享内存
- 使用内存映射文件来共享数据
- 已成功与服务器建立连接 但是在登录过程中发生错误。 provider 共享内存提供程序 error 0 管道的另一端上无任何进程。