[Linux] プロセス間通信 - 共有メモリ

[Linux]system V 共有メモリ


共有メモリは、Linux システムにおけるプロセス間通信方式であり、System V 標準に準拠しています。System V 標準の通信方式インターフェイスは、セマフォ、共有メモリ、メッセージ キューという 3 つの通信メカニズムを含め、使用法が似ています。

共有メモリ通信の原理

共有メモリは、オペレーティング システムによってメモリ内に割り当てられた空間であり、プロセスはメモリを自身のプロセス アドレス空間の共有領域にマッピングし、このマッピングを通じて共有メモリにデータを書き込んだり読み込んだりして、相互間のデータ共有を完了します。プロセスコミュニケーション。

画像-20230910185150016

通信が完了したら、プロセスはまず関係のマップを解除し、次にオペレーティング システムに共有メモリを解放させる必要があります。

システムインターフェース

共有メモリインターフェイスの作成

Linux システムは、shmget共有メモリを作成するためのインターフェイスを提供します。

//shmget所在的头文件和声明
#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);
  • 成功した場合は共有メモリ番号が返されshmid、失敗した場合は -1 が返され、エラー コードが設定されます。

キーパラメータ

共有メモリは、オペレーティング システムがメモリ内に適用するメモリ空間です。オペレーティング システムには大量の共有メモリが存在する場合があります。これらの共有メモリを管理するには、オペレーティング システムは、対応する構造を使用してメモリを記述する必要があります。メモリ内には共有メモリを一意に識別するフィールドがあり、このフィールドはkey参数渡された値を使用します。プロセスが共有メモリを使用して通信する前に、あるプロセスが共有メモリを作成してkey参数書き込み、その後、そのプロセスと通信する別のプロセスが同じ方法を使用して、それをkey参数オペレーティング システムの共有メモリ記述構造とkey参数比較して、対応する共有を見つけます。 .通信するための記憶。

画像-20230910193529432

使用されるパラメータをkey一意にし、プロセスによって使用される共有メモリが間違っていないことを保証するために、ftokシステム インターフェイスを使用します。

//ftok所在的头文件和声明
#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);
  • ftok渡されたパラメータに基づいて、非常に低い繰り返し率で数値を返すためにアルゴリズムが使用されます。
  • 成功した場合は 0、失敗した場合は -1 を返し、エラー コードが設定されます。

サイズパラメータ

size参数作成する共有メモリのサイズをバイト単位で指定するために使用されます。

オペレーティング システムは 4KB 単位page页で。

shmflgパラメータ

shmflg参数shmget使用パターンを示すために使用されます。

  • IPC_CREAT: 共有メモリを作成します。共有メモリが存在しない場合は作成し、既に存在する場合は既存の共有メモリを取得して返します。
  • IPC_EXCL単独で使用することはできず、組み合わせて使用​​する必要がありますIPC_CREAT
  • IPC_CREAT | IPC_EXCL: 共有メモリを作成します。共有メモリが存在しない場合は、作成します。すでに存在する場合は、すぐにエラーが返されます。作成が成功した場合、対応する shm は最新である必要があります。
  • 渡すことで、umask作成される共有メモリのアクセス許可を設定できます。

連想共有メモリインターフェイス

共有メモリを使用するには、共有メモリを関連付け、共有メモリを独自のプロセス アドレス空間にマップする必要があります。Linux システムは、shmat共有メモリを関連付けるインターフェイスを提供します。

//shmat所在的头文件和声明
#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);
  • shmid パラメータ – 関連付けられる共有メモリ番号を示すために使用されます。
  • shmaddr パラメータ – 関連付けられるアドレスを指定します。ヌル ポインタを渡すと、オペレーティング システム自体が関連付けを実行します。
  • shmflg パラメータ – 関連付けられる共有メモリのアクセス許可を示します。読み取りおよび書き込みアクセス許可には 0 を渡します。
  • プロセスのアドレス空間にマッピングされた共有メモリのアドレスが正常に返され、失敗した場合は -1 が返され、エラー コードが設定されます。

共有メモリインターフェイスの関連付けを解除する

共有メモリを通信に使用した後は、共有メモリの関連付けを解除する必要があります。Linux システムは、shmdt共有メモリの関連付けを解除するためのインターフェイスを提供します。

//shmdt所在的头文件和声明
#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);
  • shmaddr パラメータ – 関連付けられる共有メモリのアドレス、つまり、shmat関連付けられた共有メモリが呼び出されたときに返されるアドレス。
  • 成功した場合は 0、失敗した場合は -1 を返し、エラー コードが設定されます。

共有メモリインターフェイスの削除

Linux システムは、shmctl共有メモリを制御するためのインターフェイスを提供します。

//shmctl所在的头文件和声明
#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • shmid パラメータ – 制御される共有メモリ番号を示すために使用されます。
  • cmd パラメータ – 制御オプションを指定するために使用されます。IPC_RMIDオプションは共有メモリを削除することです。
  • buf パラメータ – 出力パラメータ。共有メモリを記述する構造情報を受け取るために使用されます。

命令を使用して共有メモリを操作する

共有メモリを表示する

Linux システムでこれを使用して、ipcs -mシステム内の共有メモリを表示します。

画像-20230910203751843

  • key:shmgetプロセスが共有メモリを作成するために呼び出すときに渡されますkey参数
  • shmid:共有メモリ番号。
  • owner: 共有メモリの所有者。
  • perms: 共有メモリに対する所有者の権限。
  • bytes: 共有メモリのサイズ。

共有メモリを削除する

Linux システムで使用して、ipcrm -m 对应shmid対応する共有メモリを削除します。

画像-20230910204051386

共有メモリ機能

  • 追加のコピーは不要: 共有メモリ通信にはインターフェイスを使用する必要がなく、共有メモリがプロセスのアドレス空間にマップされている限り、プロセスは共有メモリを参照できます。
  • 高速: 共有メモリはプロセスのアドレス空間にマップされ、プロセスは共有メモリを参照できます。バッファは関与せず、冗長コピーも必要ないため、共有メモリ通信は非常に高速です。
  • 保護なし: 共有メモリを使用した通信にはインターフェイスを使用する必要がないため、共有メモリに対する保護メカニズムはありません。

コーディングテスト用共有メモリ

common.hpp共有メモリをテストするコードを作成する前に、 、server.ccの 3 つのファイルを作成しますclient.cc

common.hpp共有メモリを使用するクラスやインターフェースを実装するために使用され、具体的な内容は次のとおりです。

#ifndef __COMN_HPP__
#define __COMM_HPP__

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <unistd.h>

using namespace std;

#define PATHNAME "."
#define PROJID 0x6666

#define gsize 4096

//key_t类型实际也是int类型
key_t GetKey()//获取key值
{
    
    
    key_t k = ftok(PATHNAME, PROJID);
    if(k == -1)//错误检测
    {
    
    
        cerr << "errno: " << errno << " strerror: " << strerror(errno) << endl;
        exit(1);
    }
    return k;
}

//只在本文件生效
static int createShmHelper(key_t key, size_t size, int shmflg)
{
    
    
    int shmid = shmget(key, size, shmflg);
    if(shmid == -1)//错误检测
    {
    
    
        cerr << "errno: " << errno << " strerror: " << strerror(errno) << endl;
        exit(2);
    }
    return shmid;
}

int createShm(key_t k, int size)
{
    
    
    umask(0);
    return createShmHelper(k, size, IPC_CREAT | IPC_EXCL | 0666);
}

int getShm(key_t k, int size)
{
    
    
    return createShmHelper(k, size, IPC_CREAT);
}

void* attachShm(int shmid)
{
    
    
    void* start = shmat(shmid, NULL, 0);
    return start;
}

void detachShm(void* start)
{
    
    
    int n = shmdt(start);
    assert(n != -1);
    (void)n;
}

void delShm(int shmid)
{
    
    
    int n = shmctl(shmid, IPC_RMID, nullptr);
    assert(n != -1);
    (void)n;
}

#define SERVER 1
#define CLIENT 0    

class  Shm
{
    
    
public:
    Shm(int type):_type(type)
    {
    
    
        key_t key = GetKey();
        if (_type == SERVER) _shmid = createShm(key, gsize);
        else _shmid = getShm(key, gsize);
        _start = attachShm(_shmid);
    }
    void* getStart()
    {
    
    
        return _start;
    }
    ~Shm()
    {
    
    
        detachShm(_start);
        if (_type == SERVER) delShm(_shmid);
    }
private:
    void* _start;
    int _shmid;
    int _type;
};

#endif

server.cc共有メモリの作成、共有メモリ内のデータの読み取り、共有メモリの解放の完了に使用され、具体的な内容は次のとおりです。

#include "common.hpp"

int main()
{
    
    
    Shm shm(SERVER);
    char* start = (char*)shm.getStart();

    int n = 0;
    while(n < 30)
    {
    
    
        cout << "client send me : " << start << endl;
        n++;
        sleep(1);
    }
    return 0;
}

client.cc共有メモリにデータを書き込むために使用され、具体的な内容は次のとおりです。

#include "common.hpp"

int main()
{
    
    
    Shm shm(CLIENT);
    char* start = (char*)shm.getStart();

    char ch = 'a';
    while(ch <= 'z')
    {
    
    
        start[ch - 'a'] = ch;
        ch++;
        start[ch - 'a'] = 0;
        sleep(1);
    }
    return 0;
}

コードをコンパイルして実行し、結果を確認します。

共有メモリ

おすすめ

転載: blog.csdn.net/csdn_myhome/article/details/132806063