共有メモリ
mmap, munmap, msync関数
mmap関数は、ファイルまたはPosixの共有メモリオブジェクトを、呼び出したプロセスのアドレス空間にマップする。mmapの3つの目的
#include <sys/mman.h> void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); 戻り値:成功ならマップされた領域の先頭アドレス、エラーならMAP_FAILED
プロセスのアドレス空間からメモリマップされた領域を取り除くにはmunmapを呼び出す
#include <sys/mman.h> int munmap(void *addr, size_t n);
ディスク上のファイルが、メモリマップされた領域と同一の内容を持っていることを保障したい場合、msyncを呼び出して強制的に同期を行わせることが出来る。
#include <sys/mman.h> int msync(void *addr, size_t len, int flags); 戻り値:成功なら0、エラーなら−1
flags引数
MS_ASYNCはカーネル書き込み操作をキューイングする。
MS_SYNCは書き込みが完了してから制御を戻す。
//複数のプロセスから、mmapによる //メモリマップファイル中のカウンタを増加させる。 #include <semaphore.h> #include <stdio.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <sys/mman.h> #define SEM_NAME "/sem" #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) sem_t *sem; int counter = 0; int main() { int fd, i, nloop, zero = 0; int *ptr; sem_t *mutex; nloop = 1000; fd = open("/tmp/mmap", O_RDWR|O_CREAT, FILE_MODE); write(fd, &zero, sizeof(int)); ptr = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); close(fd); mutex = sem_open(SEM_NAME, O_CREAT|O_EXCL, FILE_MODE, 1); sem_unlink(SEM_NAME); setbuf(stdout, NULL); if (fork() == 0) {//Child for (i = 0; i < nloop; i++) { sem_wait(mutex); (*ptr)++; (*ptr)--; (*ptr)++; printf("child: %d\n", *ptr); sem_post(mutex); } exit(0); } //Parent for (i = 0; i < nloop; i++) { sem_wait(mutex); (*ptr)++; (*ptr)--; (*ptr)++; printf("parent: %d\n", *ptr); sem_post(mutex); } return 0; }
コンパイル、実行
>gcc -lrt mmap.c
>./a.out
メモリベースセマフォによるメモリマップファイル上のカウンタの増加
#include <semaphore.h> #include <stdio.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <sys/mman.h> #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) struct shared { sem_t mutex; int count; } shared; int main() { int fd, i, nloop; struct shared *ptr; nloop = 10000; fd = open("/tmp/mmap", O_RDWR|O_CREAT, FILE_MODE); write(fd, &shared, sizeof(struct shared)); ptr = mmap(NULL, sizeof(struct shared), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); close(fd); /* Memory based semaphore */ sem_init(&ptr->mutex, 1, 1); setbuf(stdout, NULL); if (fork() == 0) { for (i = 0; i < nloop; i++) { sem_wait(&ptr->mutex); ptr->count++; ptr->count--; ptr->count++; printf("child: %d\n", ptr->count); sem_post(&ptr->mutex); } exit(0); } for (i = 0; i < nloop; i++) { sem_wait(&ptr->mutex); ptr->count++; ptr->count--; ptr->count++; printf("parent: %d\n", ptr->count); sem_post(&ptr->mutex); } return 0; }
//メモリマップファイルをftruncateで拡張する #include <sys/mman.h> #include <stdio.h> #include <fcntl.h> #include <sys/stat.h> #define FILE "/tmp/mmap" #define SIZE 32768 #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) int main() { int fd, i; char *ptr; fd = open(FILE, O_RDWR|O_CREAT|O_TRUNC, FILE_MODE); ptr = mmap(NULL, SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); for (i = 4096; i <= SIZE; i += 4096) { printf("setting file size to %d\n", i); ftruncate(fd, i); printf("ptr[%d] = %d\n", i-1, ptr[i-1]); } return 0; }