コンピューター:C言語講座:共有メモリについて
概要
共有メモリは複数のプロセスで共有できるメモリで、プロセス間通信で最もシンプルで高速なものではないかと思います。使い道としては複数のプロセスでデータを共有したり、メッセージやフラグとして使用するのにも良いと思います。
UNIXでは共有メモリを含むプロセス間通信機能をまとめてIPC(Inter
Process communication)として管理しており、メッセージキュー・共有メモリ・セマフォがそのなかに含まれます。ipcsコマンドを使用するとそれらの使用状況をみることが出来ます。
使用方法
共有メモリの使用方法は非常に簡単で、shmget()システムコールで共有メモリ・セグメント識別子を獲得し、shmat()システムコールで自プロセスのデータセグメントにマップ(アタッチとも呼ぶ)します。他のプロセスも識別子さえ指定してshmat()を行なえば同じ内容を指すメモリを操作することが出来ます。
使用後はshmdt()システムコールでアンマップ(デタッチとも呼ぶ)し、共有メモリが不要であればshmctl()を使用してシステム上から削除することも出来ます。
削除はipcrmコマンドを使用して行なうことも可能です。
注意事項
共有メモリのサイズは無限にあるわけではありません。OSにより異なりますが、OS起動時から固定されます。変更することも可能ですが、メモリ内の一部をロックすることになりますので、あまり大きく確保すると他のプロセス用のメモリが減ります。
サンプル
非常に単純なサンプルですが、2つのプロセスで同じアドレスを共有し、受信側は3秒おきにそのアドレスの内容を表示し、送信側は標準入力から得た文字列を共有メモリにセットします。"end"という文字列で送受信とも終了することにします。
送信プログラムは起動時に引数で受信プログラムが表示する共有メモリIDを指定する必要があります。
<<受信プログラム>>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
void main()
{
int id;
char *adr;
if((id=shmget(IPC_PRIVATE,512,IPC_CREAT|0666))==-1){
perror("shmget");
exit(-1);
}
printf("共有メモリID=%d\n",id);
if((adr=shmat(id,0,0))==-1){
perror("shmat");
}
else{
strcpy(adr,"Initial");
while(1){
printf("%s\n",adr);
if(strcmp(adr,"end")==0){
break;
}
sleep(3);
}
if(shmdt(adr)==-1){
perror("shmdt");
}
}
if(shmctl(id,IPC_RMID,0)==-1){
perror("shmctl");
}
}
<<送信プログラム>>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
void main(argc,argv)
int argc;
char *argv[];
{
int id;
char *adr;
if(argc<=1){
fprintf(stderr,"共有メモリIDを引数に指定すること。\n");
exit(-1);
}
id=atoi(argv[1]);
if((adr=shmat(id,0,0))==-1){
perror("shmat");
}
else{
while(1){
gets(adr);
if(strcmp(adr,"end")==0){
break;
}
}
if(shmdt(adr)==-1){
perror("shmdt");
}
}
}
ソケット・パイプ・FIFOなどに比べて単純な割にしっかりメッセージが共有できてありがたいのですが、内容を更新したタイミングを得るのが難しいのと、サイズが固定となる為、やはり通信というイメージとは少し異なった感じです。