mmap函数参数讲解

1.mmap-创建内存映射

    作用:将磁盘文件的数据映射到内存,用户通过内存就能修改磁盘文件

    函数原型:

 
  1. void *mmap{

  2. void *addr; //映射区首地址,传NULL

  3. size_t length; //映射区的大小

  4. //会自动调为4k的整数倍

  5. //不能为0

  6. //一般文件多大,length就指定多大

  7. int prot; //映射区权限

  8. //PROT_READ 映射区比必须要有读权限

  9. //PROT_WRITE

  10. //PROT_READ | PROT_WRITE

  11. int flags; //标志位参数

  12. //MAP_SHARED 修改了内存数据会同步到磁盘

  13. //MAP_PRIVATE 修改了内存数据不会同步到磁盘

  14. int fd; //要映射的文件对应的fd

  15. off_t offset; //映射文件的偏移量,从文件的哪里开始操作

  16. //映射的时候文件指针的偏移量

  17. //必须是4k的整数倍

  18. //一般设置为0

  19.  
  20. }

返回值:

映射区的首地址-调用成功

调用失败:MAP_FALED

2.munmap-释放内存映射区

函数原型:int munmap(void *addr,size_t length);

    addr-mmap的返回值

    length-mmap的第二个参数

3.注意事项

问:如果对mmap的返回值(ptr)做++操作(ptr++), munmap是否能够成功?
答:不能
问:如果open时O_RDONLY, mmap时prot参数指定PROT_READ | PROT_WRITE会怎样?
答mmap调用失败
open文件指定权限应该大于等于mmap第三个参数prot指定的权限
问:如果文件偏移量为1000会怎样?
答:必须是4096的整数倍
问:mmap什么情况下会调用失败?
第二个参数length = 0
第三个参数必须指定PROT_READ
fd对应的打开权限必须大于等于port权限
偏移量:必须是4096的整数倍
问:可以open的时候O_CREAT一个新文件来创建映射区吗?
答:可以,需要做文件拓展
lseek
truncate(path,length)
问:mmap后关闭文件描述符,对mmap映射有没有影响?
答:没有
问:对ptr越界操作会怎样?
答:段错误

4.mmap使用

(1)基本代码

 
  1. #include

  2. #include

  3. #include

  4. #include

  5. #include

  6. #include

  7. #include

  8. #include

  9.  
  10. int main(int argc, const char* argv[])

  11. {

  12. //打开一个文件

  13. int fd=open("english.txt",O_RDWR);

  14. int len=lseek(fd,0,SEEK_END);

  15.  
  16. //创建内存映射区

  17. void *ptr=mmap(NULL,len,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);

  18. if(ptr==MAP_FAILED)

  19. {

  20. perror("mmap error");

  21. exit(1);

  22. }

  23.  
  24. printf("%s",(char*)ptr);

  25.  
  26. //释放内存映射区

  27. munmap(ptr,len);

  28. close(fd);

  29. return 0;

  30. }

运行结果:

 
  1. wangkai@wangkai-HP-242-G1-Notebook-PC:~/0110/6Day$ ./mmap

  2. sadaskdkasj

  3. sdasdasd

  4. asdasdsadasds

  5. dasdas

(2)使用mmap进行有血缘关系的进程间通信

 
  1. #include

  2. #include

  3. #include

  4. #include

  5. #include

  6. #include

  7. #include

  8. #include

  9. #include

  10.  
  11. /*

  12. 利用mmap进行父子间通信,效率比文件I/O高,

  13. 数据不是从磁盘上读,而是从内存上读写

  14.  
  15. 不阻塞,所以读之前一定要写好

  16. */

  17. int main(int argc, const char* argv[])

  18. {

  19. //打开一个文件

  20. int fd=open("english.txt",O_RDWR);

  21. int len=lseek(fd,0,SEEK_END);

  22.  
  23. //创建内存映射区

  24. void *ptr=mmap(NULL,len,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);

  25. if(ptr==MAP_FAILED)

  26. {

  27. perror("mmap error");

  28. exit(1);

  29. }

  30.  
  31. close(fd);

  32. //创建子进程

  33. pid_t pid=fork();

  34. if(pid==-1)

  35. {

  36. perror("fork error");

  37. exit(1);

  38. }

  39. if(pid>0)

  40. {

  41. //写数据

  42. strcpy((char*)ptr,"我是你爸爸");

  43. //回收子进程

  44. wait(NULL);

  45. }

  46. else if(pid==0)

  47. {

  48. //读数据

  49. printf("%s\n",(char*)ptr);

  50. }

  51. printf("%s",(char*)ptr);

  52.  
  53. //释放内存映射区

  54. munmap(ptr,len);

  55.  
  56. return 0;

  57. }

(3)创建匿名映射区

 
  1. int len=4096;

  2. //创建匿名内存映射区,不指定文件

  3. void *ptr=mmap(NULL,len,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANON,-1,0);

效果和(2)一样。

(4)没有血缘关系的进程间通信

写代码

 
  1. //mmap_w_ipc.c

  2. #include

  3. #include

  4. #include

  5. #include

  6. #include

  7. #include

  8. #include

  9.  
  10.  
  11. int main(int argc, char *argv[])

  12. {

  13. int fd = open("temp", O_RDWR | O_CREAT, 0664);

  14.  
  15. void* ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

  16. if(ptr == MAP_FAILED)

  17. {

  18. perror("mmap");

  19. exit(1);

  20. }

  21.  
  22. while(1)

  23. {

  24. char*p = (char*)ptr;

  25. p += 1024;

  26. strcpy(p, "hello parent, i am your 朋友!!!\n");

  27. sleep(2);

  28. }

  29.  
  30. // 释放

  31. int ret = munmap(ptr, 8192);

  32. if(ret == -1)

  33. {

  34. perror("munmap");

  35. exit(1);

  36. }

  37.  
  38. return 0;

  39. }

  40.  

 

读代码

 
  1. //mmap_r_ipc.c

  2. #include

  3. #include

  4. #include

  5. #include

  6. #include

  7. #include

  8. #include

  9.  
  10.  
  11. int main(int argc, char *argv[])

  12. {

  13. int fd = open("temp", O_RDWR | O_CREAT, 0664);

  14. ftruncate(fd, 4096);

  15. int len = lseek(fd, 0, SEEK_END);

  16.  
  17. void* ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

  18. if(ptr == MAP_FAILED)

  19. {

  20. perror("mmap");

  21. exit(1);

  22. }

  23.  
  24. while(1)

  25. {

  26. sleep(1);

  27. printf("%s\n", (char*)ptr+1024);

  28. }

  29.  
  30. // 释放

  31. int ret = munmap(ptr, len);

  32. if(ret == -1)

  33. {

  34. perror("munmap");

  35. exit(1);

  36. }

  37.  
  38. return 0;

  39. }

  40.  
  41.  

小结

 

1. 进程间通信

    a. 有血缘关系的
父子进程共享内存映射区
    b. 没有血缘关系的进程间通信
i. 如何通信?
不能使用匿名映射的方式
只能借助磁盘文件创建映射区 - hello
不阻塞
ii. a(a.c)  b(b.c)
a.c
int fd = open("hello");
void* ptr = mmap(,,,,,fd, 0);
对映射区进行读写操作

b.c
int fd1 = open("hello");
void* ptr1 = mmap(,,,,fd1, 0);

对映射区做读写操作

2. mmap 实现内存映射

a. 必须有一个文件
b. 文件数据什么时候有用:
i. 单纯文件映射
ii. 进程间通信:
1) 文件数据是没有用的

3. 如果创建匿名映射区

mmap的时候:
    第二个参数:指定映射区大小
    第四个参数:需要添加MAP_ANON宏
    第五个参数:-1

4. 父子进程永远共享的东西?

文件描述符
内存映射区

你可能感兴趣的:(linux)