您的位置:首页 > 运维架构 > Linux

共享内存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



说明:shmat函数将指定共享内存标识符为shmid的共享内存段连接到进程地址空间中。参数shmid为要连接的共享内存段标识符。shmaddr为连接的内存地址,并遵循如下的原则

 

(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



说明:shmdt函数用于在完成对共享内存段操作后,实现共享内存段与进程空间的分离。该函数并没有删除共享内存段。参数shmaddr为调用shmat函数后获得的地址指针。

 

错误信息:

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]#


 

说明:由于不存在多线程同时访问的问题,不存在保护共享内存段的问题。当存在多线程同时对共享内存进行访问时,必须使用信号量来进行进程间互斥。

 

 

 

 

 

 

 

 

 

 

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息