Linux C-共有メモリ


一、共有メモリ実現の原理、システムV実現の関数
1.共有メモリ実現の原理
システムV共有メモリとは、共有データを共有メモリ領域に格納することである(IPC shared memory region)データにアクセスしたいプロセスは、メモリ領域を共有することによってアクセス権を取得します.システムV共有メモリは、shmgetによってIPC共有メモリ領域を取得または作成し、対応する識別子を返します.カーネルは、shmgetが共有メモリ領域を取得または作成することを保証し、共有メモリ領域に対応するshmid_kernel構造注記を初期化します.また、特殊なファイルシステムshmでは、同じ名前のファイルを作成して開き、メモリにファイルの対応するdentryおよびinode構造を構築します.新しく開いたファイルは、どのプロセスにも属しません(どのプロセスでも共有メモリ領域にアクセスできます).これらはすべてシステムがshmgetを呼び出して完了します.
注意:共有メモリ領域ごとに制御構造struct shmid_があります.kernel,shmid_kernelは共有メモリ領域において非常に重要なデータ構造であり、ストレージ管理とファイルシステムを組み合わせた橋渡しであり、以下のように定義されています.
struct shmid_kernel /* private to the kernel */
{
struct kern_ipc_perm shm_perm;
struct file * shm_file;
int id;
unsigned long shm_nattch;
unsigned long shm_segsz;
time_t shm_atim;
time_t shm_dtim;
time_t shm_ctim;
pid_t shm_cprid;
pid_t shm_lprid;
};

この構造で最も重要なドメインはshm_であるべきである.ファイルは、マッピングされるファイルのアドレスを格納します.各共有メモリ領域オブジェクトは、特殊ファイルシステムshmの1つのファイルに対応しており、一般的に、特殊ファイルシステムshmのファイルはread()やwrite()などの方法でアクセスできないため、共有メモリ方式でそのファイルをプロセスアドレス空間にマッピングした後、直接メモリにアクセスする方式でアクセスすることができる.
メッセージキューや信号灯のように、カーネルはデータ構造struct ipc_を通過します.ids shm_idsは、システム内のすべての共有メモリ領域を維持します.shm_idsのentries変数はipc_を指すid構造配列、各ipc_id構造配列にkern_を指すipc_perm構造のポインタ.そしてkern_ipc_permの宿主はshmid_kernel構造、shmid_kernelは、カーネルがシステム内のすべての共有領域を制御できるように、共有メモリ領域を記述するために使用される.同時にshmid_kernel構造のfileタイプポインタshm_fileはファイルシステムshm内の対応するファイルを指し、共有メモリ領域はshmファイルシステム内のファイルに対応する.
共有メモリ領域を作成した後、shmat()をシステム呼び出してこの機能を完了するプロセスアドレス空間にマッピングします.shmget()を呼び出すと、ファイルシステムshmの同名ファイルが共有メモリ領域に対応するように作成されているため、shmat()を呼び出すプロセスは、マッピングファイルシステムshmの同名ファイルプロセスに相当する.
 
2.system V実現の関数
①shmget関数
ファンクションヘッダファイル
#include #include
関数プロトタイプ
int shmget(key_t key, size_t size, int shmflg)
関数パラメータ
key
0(IPC_PRIVATE):新しい共有メモリオブジェクトが0より大きい32ビット整数が確立されます.パラメータshmflgによってアクションが決定されます.通常、この値はftokが返すIPCキー値に由来する必要があります.
size
0より大きい整数:新規共有メモリサイズ、バイト単位0:共有メモリのみ取得時0
shmflg
0:共有メモリ識別子を取得し、存在しない場合、関数はIPC_をエラーします.CREAT:shmflg&IPC_CREATが真の場合、カーネルにキー値とkeyが等しい共有メモリが存在しない場合は、新しい共有メモリを作成します.このような共有メモリが存在する場合、この共有メモリの識別子IPC_を返すCREAT|IPC_EXCL:カーネルにキー値がkeyと等しい共有メモリが存在しない場合、新しい共有メモリを作成します.このような共有メモリが存在する場合、エラーが発生します.
戻り値
成功:共有メモリの識別子を返すエラー:-1、エラーの原因はerrorに保存されます
 
②shmat関数
ファンクションヘッダファイル
#include #include
関数プロトタイプ
void *shmat(int shmid, const void *shmaddr, int shmflg)
関数パラメータ
  shmid
共有メモリ識別子
shmaddr
共有メモリがプロセスメモリアドレスのどこに表示されるかを指定し、NULLに直接指定してカーネル自身に適切なアドレス位置を決定させる
shmflg
SHM_RDONLY:読み取り専用モード、その他は読み書きモード
戻り値
成功:追加された共有メモリアドレスエラー:-1、エラー原因errnoに保存
 
③shctl関数
ファンクションヘッダファイル
#include #include
関数プロトタイプ
int shmdt(const void *shmaddr)
関数パラメータ
 shmaddr
接続された共有メモリの開始アドレス
戻り値
成功:追加された共有メモリアドレスエラー:-1、エラー原因errnoに保存
 
 
二、system v共有メモリは親子プロセスと血縁関係がない間にどのように通信しますか?
1.親子プロセス
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
#define PERM S_IRUSR|S_IWUSR
/*      */
 
int main(int argc,char **argv)
{
int shmid;
char *p_addr,*c_addr;
if(argc!=2)
{
fprintf(stderr,"Usage:%s
\a",argv[0]); exit(1); } /* */ if((shmid=shmget(IPC_PRIVATE,1024,PERM))==-1) { fprintf(stderr,"Create Share Memory Error:%s
\a",strerror(errno)); exit(1); } /* */ if(fork()) // { p_addr=shmat(shmid,0,0); memset(p_addr,'\0',1024); strncpy(p_addr,argv[1],1024); wait(NULL); // , exit(0); } else // { sleep(1); // 1 c_addr=shmat(shmid,0,0); printf("Client get %s
",c_addr); exit(0); } }

2.関係のないプロセスで
①データを読む
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "shm_com.h"
 
int main(void)
{
    int running=1;
void *shared_memory=(void *)0;
struct shared_use_st *shared_stuff;
int shmid;
 
 
/*      */
shmid=shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT);
if(shmid==-1)
{
    fprintf(stderr,"shmget failed
"); exit(EXIT_FAILURE); } /* */ shared_memory=shmat(shmid,(void *)0,0); if(shared_memory==(void *)-1) { fprintf(stderr,"shmat failed
"); exit(EXIT_FAILURE); } printf("Memory attached at %X
",(int)shared_memory); /* */ shared_stuff=(struct shared_use_st *)shared_memory; /* */ shared_stuff->written_by_you=0; /* , “end” */ while(running) { if(shared_stuff->written_by_you) { printf("You wrote:%s",shared_stuff->some_text); sleep(1); // , , shared_stuff->written_by_you=0; if(strncmp(shared_stuff->some_text,"end",3)==0) { running=0; // } } } /* */ if(shmdt(shared_memory)==-1) { fprintf(stderr,"shmdt failed
"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } ② #include #include #include #include #include #include #include #include "shm_com.h" int main(void) { int running=1; void *shared_memory=(void *)0; struct shared_use_st *shared_stuff; char buffer[BUFSIZ]; int shmid; /* */ shmid=shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT); if(shmid==-1) { fprintf(stderr,"shmget failed
"); exit(EXIT_FAILURE); } /* */ shared_memory=shmat(shmid,(void *)0,0); if(shared_memory==(void *)-1) { fprintf(stderr,"shmat failed
"); exit(EXIT_FAILURE); } printf("Memory attached at %X
",(int)shared_memory); /* */ shared_stuff=(struct shared_use_st *)shared_memory; /* , “end” */ while(running) { while(shared_stuff->written_by_you==1) { sleep(1);// printf("waiting for client...
"); } printf("Ener some text:"); fgets(buffer,BUFSIZ,stdin); strncpy(shared_stuff->some_text,buffer,TEXT_SZ); shared_stuff->written_by_you=1; if(strncmp(buffer,"end",3)==0) { running=0; // } } /* */ if(shmdt(shared_memory)==-1) { fprintf(stderr,"shmdt failed
"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }