【共有メモリ】

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: 共有メモリID
shmaddr: 接続のアドレスを指定します。指定しない場合は、ビットを空に設定します。
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

共有メモリには相互排他同期メカニズムがありません。つまり、データを書き込むときにデータを直接読み取ることができます。同期メカニズムを拒否して、後でマルチスレッドでこれを追加します。

おすすめ

転載: blog.csdn.net/m0_68872612/article/details/130239114