内存映射的应用:
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
void *mmap64(void *addr, size_t length, int prot, int flags,
int fd, off64_t offset);
int munmap(void *addr, size_t length);
int msync(void *addr, size_t length, int flags);
参数 addr 指明文件描述字fd指定的文件在进程地址空间内的映射区的开始地址,必须是页面对齐的地址,通常设为 NULL,让内核去选择开始地址。任何情况下,mmap 的返回值为内存映射区的开始地址。
参数 length 指明文件需要被映射的字节长度。off 指明文件的偏移量。通常 off 设为 0 。
参数 prot 指明映射区的保护权限。通常有以下 4 种。通常是 PROT_READ | PROT_WRITE 。
参数 flag 指明映射区的属性。取值有以下几种。MAP_PRIVATE 与 MAP_SHARED 必选其一,MAP_FIXED 为可选项。
当 mmap 成功返回时,fd 就可以关闭,这并不影响创建的映射区。
进程退出的时候,映射区会自动删除。不过当不再需要映射区时,可以调用 munmap 显式删除。当映射区删除后,后续对映射区的引用会生成 SIGSEGV 信号。
文件一旦被映射后,调用mmap()的进程对返回地址的访问是对某一内存区域的访问,暂时脱离了磁盘上文件的影响。所有对mmap()返回地址空间的操作只在内存中有意义,只有在调用了munmap()后或者msync()时,才把内存中的相应内容写回磁盘文件。
map_normalfile1.c及map_normalfile2.c。编译两个程序,可执行文件分别为map_normalfile1及map_normalfile2。两个程序通过命令行参数指定同一个文件来实现共享内存方式的进程间通信。map_normalfile2试图打开命令行参数指定的一个普通文件,把该文件映射到进程的地址空间,并对映射后的地址空间进行写操作。map_normalfile1把命令行参数指定的文件映射到进程地址空间,然后对映射后的地址空间执行读操作。这样,两个进程通过命令行参数指定同一个文件来实现共享内存方式的进程间通信。
/*-------------map_normalfile1.c-----------*/
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
typedef struct{
char name[4];
int age;
}people;
int main(int argc, char** argv) // map a normal file as shared mem:
{
int fd,i;
people *p_map;
char temp[2] = {‘\0‘};
fd=open(argv[1],O_CREAT|O_RDWR|O_TRUNC,00777);
lseek(fd,sizeof(people)*5-1,SEEK_SET);
write(fd,"",1);
p_map = (people*) mmap( NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,
MAP_SHARED,fd,0 );
close( fd );
temp[0] = ‘a‘;
for(i=0; i<15; i++)
{
temp[0] += 1;
memcpy( ( *(p_map+i) ).name, &temp[0],2 );
( *(p_map+i) ).age = 20+i;
}
printf("initialize over\n");
sleep(10);
munmap( p_map, sizeof(people)*10 );
printf( "umap ok \n" );
return 0;
}
/*-------------map_normalfile2.c-----------*/
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
typedef struct{
char name[4];
int age;
}people;
int main(int argc, char** argv) // map a normal file as shared mem:
{
int fd,i;
people *p_map;
char temp[2] = {‘\0‘};
fd=open(argv[1],O_CREAT|O_RDWR|O_TRUNC,00777);
lseek(fd,sizeof(people)*5-1,SEEK_SET);
write(fd,"",1);
p_map = (people*) mmap( NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,
MAP_SHARED,fd,0 );
close( fd );
temp[0] = ‘a‘;
for(i=0; i<15; i++)
{
temp[0] += 1;
memcpy( ( *(p_map+i) ).name, &temp[0],2 );
( *(p_map+i) ).age = 20+i;
}
printf("initialize over\n");
sleep(10);
munmap( p_map, sizeof(people)*10 );
printf( "umap ok \n" );
return 0;
}
map_normalfile1首先打开或创建一个文件,并把文件的长度设置为5个people结构大小.mmap映射10个people结构大小的内存,利用返回的地址开始设置15个people结构。然后睡眠10S,等待其他进程映射同一个文件,然后解除映射。
通过实验,在map_normalfile1输出initialize over 之后,输出umap ok之前,运行map_normalfile2 file,可以输出设置好的15个people结构
在map_normalfile1 输出umap ok后,运行map_normalfile2则输出结构,前5个people是已设置的,后10结构为0。
1) 最终被映射文件的内容的长度不会超过文件本身的初始大小,即映射不能改变文件的大小.
2) 可以用于进程通信的有效地址空间大小大体上受限于被映射文件的大小,但不完全受限于文件大小.打开文件的大小为5个people结构,映射长度为10个people结构长度,共享内存通信用15个people结构大小。
在linux中,内存的保护是以页为基本单位的,即使被映射文件只有一个字节大小,内核也会为映射分配一个页面大小的内存。当被映射文件小于一个页面大小时,进程可以对从mmap()返回地址开始的一个页面大小进行访问,而不会出错;但是,如果对一个页面以外的地址空间进行访问,则导致错误发生,后面将进一步描述。因此,可用于进程间通信的有效地址空间大小不会超过文件大小及一个页面大小的和。
3) 文件一旦被映射后,调用mmap()的进程对返回地址的访问是对某一内存区域的访问,暂时脱离了磁盘上文件的影响。所有对mmap()返回地址空间的操作只在内存中有意义,只有在调用了munmap()后或者msync()时,才把内存中的相应内容写回磁盘文件,所写内容仍然不能超过文件的大小
技巧:
生成固定大小的文件的两种方式:
/*第一种方法*/
fd = open(PATHNAME, O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);
lseek(fd, filesize-1, SEEK_SET);
write(fd, "", 1);
/*第二种方法*/
ftruncate(fd, filesize);
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
typedef struct{
char name[4];
int age;
}people;
main(int argc, char** argv)
{
int i;
people *p_map;
char temp;
p_map=(people*)mmap(NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_ANONYMOUS,-1,0);
if(fork() == 0)
{
sleep(2);
for(i = 0;i<5;i++)
printf("child read: the %d people‘s age is %d\n",i+1,(*(p_map+i)).age);
(*p_map).age = 100;
munmap(p_map,sizeof(people)*10); //实际上,进程终止时,会自动解除映射。
exit();
}
temp = ‘a‘;
for(i = 0;i<5;i++)
{
temp += 1;
memcpy((*(p_map+i)).name, &temp,2);
(*(p_map+i)).age=20+i;
}
sleep(5);
printf( "parent read: the first people,s age is %d\n",(*p_map).age );
printf("umap\n");
munmap( p_map,sizeof(people)*10 );
printf( "umap ok\n" );
}
参考:
man pthread_mutexattr_init
查看信号量进程间同步实现实例版权声明:本文为博主原创文章,转载请注明出处
原文地址:http://blog.csdn.net/callinglove/article/details/46710465