1 共有メモリの概念図
共有メモリ領域は、 IPC の最も高速な 形式です。このようなメモリが、それを共有するプロセスのアドレス空間にマッピングされると、これらのプロセス間のデータ転送にはカーネルが関与しなくなります。つまり、プロセスは、 カーネルへのシステム コールを実行することによって相互にデータを受け渡しなくなります。
2 共有メモリのデータ構造
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
3 共有メモリ機能(強調)
- shmget関数:
機能: 共有メモリの作成に使用されます。プロトタイプ:int shmget(key_t キー、size_t サイズ、int shmflg);パラメーター:key: 共有メモリセグメントの名前。サイズ: 共有メモリのサイズ。shmflg: 9 つの許可フラグで構成され、その使用法はファイルの作成時に使用される モードフラグ と同じです。戻り値: 成功した場合は共有メモリセグメントの識別コードである非負の整数を返し、失敗した場合は -1 を返します。
shmflg には、 IPC_CREAT と IPC_EXCL という2 つの一般的に使用される許可ビットがあります。
- IPC_CREAT を単独で使用します。共有メモリを作成します。共有メモリが存在しない場合は作成し、既に存在する場合は既存の共有メモリを取得して戻ります。
- IPC_EXCL は単独で使用できず、通常は IPC_CREAT と連携する必要があります。
- IPC_CREAT | IPC_EXCL: 共有メモリを作成します。共有メモリが存在しない場合は作成されます。既に存在する場合は、すぐにエラーが返されます。作成が成功した場合、対応する shm は最新である必要があります。
この関数の最初のパラメータキーを取得するにはどうすればよいでしょうか?
ftok関数を使用できます。
戻り値を使用して、生成された key_t 型を受け取るだけです。
- shmat関数:
機能: 共有メモリセグメントをプロセスアドレス空間に接続します。プロトタイプ:void *shmat(int shmid, const void *shmaddr, int shmflg);パラメーター:shmid: 共有メモリIDshmaddr: 接続のアドレスを指定します。指定しない場合は、ビットを空に設定します。shmflg: 可能な 2 つの値は SHM_RND と SHM_RDONLY で、0 に設定することもできます。戻り値: 正常に共有メモリの最初のセクションへのポインタを返し、失敗した場合は -1を返します。
例証します:
shmaddrが NULL の場合 、コアはアドレスを自動的に選択しますshmaddr が NULL でなく 、shmflg にSHM_RNDフラグがない場合は、接続アドレスとしてshmaddr を使用します。shmaddr が NULL でなく 、shmflg がSHM_RNDフラグを設定する場合、接続されたアドレスはSHMLBAの整数倍になるまで自動的に調整されます。式: shmadr -(shmaddr % SHMLBA)shmflg=SHM_RDONLY 、接続操作が読み取り専用共有メモリに使用されることを示します。
- shmdt関数:
機能: 現在のプロセスから共有メモリセグメントを分離します。プロトタイプ:int shmdt(const void *shmaddr);パラメーター:shmaddr: shmat によって 返されるポインタ。戻り値: 成功した場合は 0を返し 、失敗した場合は -1 を返します。注: 現在のプロセスから共有メモリ セグメントを切り離すことは、共有メモリ セグメントを削除することを意味しません。
- shmctl関数:
機能: 共有メモリの制御に使用されます。プロトタイプ:int shmctl(int shmid, int cmd, struct shmid_ds *buf);パラメーター:shmid: shmget によって 返される共有メモリ識別コードcmd: 実行されるアクション (可能な値は 3 つあります)buf: 共有メモリのモード状態とアクセス権を保存するデータ構造を指します。戻り値: 成功した場合は 0を返し 、失敗した場合は -1 を返します。
4 共有メモリを使用したクライアントとサーバ間の通信の例
通信.hpp:
#include<iostream>
#include<cerrno>
#include<cstring>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<unistd.h>
using namespace std;
#define PATHNAME "."
#define PROJID 6666
key_t getKey()
{
key_t key=ftok(PATHNAME,PROJID);
if(key==-1)
{
cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
return 1;
}
return key;
}
int creatShm(size_t size,int shmflag=0)
{
umask(0);
int shmid=shmget(getKey(),size,IPC_CREAT | IPC_EXCL | 0666);
if(shmid==-1)
{
cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
return 1;
}
return shmid;
}
int getShm(size_t size,int shmflag=0)
{
int shmid=shmget(getKey(),size,IPC_CREAT );
if(shmid==-1)
{
cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
return 1;
}
return shmid;
}
char* attachShm(int shmid)
{
char* start=(char*)shmat(shmid,nullptr,0);
return start;
}
void detouchShm(char* start)
{
int n=shmdt(start);
if(n==-1)
{
cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
return ;
}
}
void delShm(int shmid)
{
int n=shmctl(shmid,IPC_RMID,nullptr);
if(n==-1)
{
cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
return ;
}
}
サーバー.cc:
#include<iostream>
#include"comm.hpp"
int main()
{
//1 创建共享内存
int shmid=creatShm(4096);
//2 将共享内存与自己关联起来
char* start=attachShm(shmid);
//3 使用共享内存通信
int cnt=0;
while(cnt<=15)
{
cout<<start<<endl;
sleep(1);
++cnt;
}
//4 解除自己与共享内存的关联
detouchShm(start);
//5 删除共享内存
delShm(shmid);
return 0;
}
client.cc:
#include<iostream>
#include"comm.hpp"
int main()
{
//1 创建共享内存
int shmid=getShm(4096);
//2 将共享内存与自己关联起来
char* start=attachShm(shmid);
//3 使用共享内存通信
char ch='A';
while(ch<='Z')
{
start[ch-'A']=ch;
++ch;
start[ch-'A']=0;
sleep(1);
}
//4 解除自己与共享内存的关联
detouchShm(start);
//客户端不要删掉共享内存
return 0;
}
このようにして、プログラムを通常どおり実行できますが、./server プロセスを誤って終了し、共有メモリが削除されなかった場合は、コマンド ラインを使用して共有メモリを削除できます。
共有メモリの表示コマンド:
ipcs -m
指定した共有メモリを削除します。
ipcrm -m 共享内存的id
共有メモリには相互排他同期メカニズムがありません。つまり、データを書き込むときにデータを直接読み取ることができます。同期メカニズムを拒否して、後でマルチスレッドでこれを追加します。