第80章 fork() でプライベートファイルマッピングのチェック

 プライベートファイルマッピングは既に軽く紹介していますが、ここでは fork() を使うことで Copy-On-Write の仕組みをより良く理解したいと思います。

 では実装例を見てみましょう。

main.c. 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <sys/mman.h>
  5 #include <sys/stat.h>
  6 #include <sys/types.h>
  7 #include <unistd.h>
  8 #include <fcntl.h>
  9
 10 #define BUF_SIZE 8
 11
 12 int main()
 13 {
 14   int fd,i;
 15   struct stat sb;
 16   char buf[BUF_SIZE];
 17   char *mm;
 18
 19   memset(buf,0,BUF_SIZE);
 20
 21   fd = open("abc.txt",O_CREAT|O_RDWR|O_TRUNC,0644);
 22   if(fd < 0) {
 23     perror("ファイルを開けません");
 24     exit(1);
 25   }
 26   write(fd,buf,BUF_SIZE);
 27   if(fstat(fd,&sb) == -1) {
 28     perror("stat");
 29     exit(1);
 30   }
 31
 32   mm = mmap(NULL,sb.st_size,PROT_WRITE|PROT_READ,MAP_PRIVATE,fd,0);
 33   if(mm == MAP_FAILED){
 34     perror("mmap");
 35     exit(1);
 36   }
 37
 38   pid_t id = fork();
 39
 40   if(id == 0) {
 41     for(i = 0; i < sb.st_size-2; i++)
 42       mm[i] = 'a'+i;
 43     mm[sb.st_size-2] = '\n';
 44     mm[sb.st_size-1] = '\0';
 45
 46   } else {
 47     for(i = 0; i < sb.st_size-2; i++)
 48       mm[i] = 'a';
 49     mm[sb.st_size-2] = '\n';
 50     mm[sb.st_size-1] = '\0';
 51   }
 52
 53   for(i = 0; i < 10; i++)
 54     printf("mm[%d] => %c\n",i,mm[i]);
 55
 56   if(munmap(mm,sb.st_size) == -1){
 57     perror("munmap");
 58     exit(1);
 59   }
 60   close(fd);
 61
 62   return 0;
 63 }

ビルドと実行結果. 

$ gcc main.c
$ ./a.out
mm[0] => a
mm[1] => a
mm[2] => a
mm[3] => a
mm[4] => a
mm[5] => a
mm[6] =>

mm[7] =>
mm[8] =>
mm[9] =>
mm[0] => a
mm[1] => b
mm[2] => c
mm[3] => d
mm[4] => e
mm[5] => f
mm[6] =>

mm[7] =>
mm[8] =>
mm[9] =>
$ cat abc.txt

 このソースコードでは「 abc.txt 」ファイルを新規生成または開いて、それを mmap() でマッピングします。

 21   fd = open("abc.txt",O_CREAT|O_RDWR|O_TRUNC,0644);
 22   if(fd < 0) {
 23     perror("ファイルを開けません");
 24     exit(1);
 25   }

 mmap() は以下のように MAP_PRIVATE を指定しています。

 32   mm = mmap(NULL,sb.st_size,PROT_WRITE|PROT_READ,MAP_PRIVATE,fd,0);
 33   if(mm == MAP_FAILED){
 34     perror("mmap");
 35     exit(1);
 36   }

 次に fork() で子プロセスを生成します。

 38   pid_t id = fork();
 39
 40   if(id == 0) {
 41     for(i = 0; i < sb.st_size-2; i++)
 42       mm[i] = 'a'+i;
 43     mm[sb.st_size-2] = '\n';
 44     mm[sb.st_size-1] = '\0';
 45
 46   } else {
 47     for(i = 0; i < sb.st_size-2; i++)
 48       mm[i] = 'a';
 49     mm[sb.st_size-2] = '\n';
 50     mm[sb.st_size-1] = '\0';
 51   }

 子プロセス( id == 0 )は a,b,c,d,e,f という並びの文字配列に設定します。

 親プロセス( id が 0 でない )の方は a,a,a,a,a,a という並びにします。

 mm は MAP_PRIVATE でアクセスをするため、親プロセスの変更と子プロセスの変更は独立して行われてますね。

Copyright 2018-2019, by Masaki Komatsu