研究ノート:道の下でのプロセス間の相互通信を実現するLinuxの共有メモリ

まず、一般的に使用される機能

関数のヘッダファイルの家族

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

ftok():

(このようなメッセージキューとして、共有メモリ)システムIPC通信はID値を指定しなければなりません。典型的には、ftok ID機能により得られた値。

key_t ftok( char * fname, int id );//当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回。

アプリケーション例:

key_t key = ftok(".", 2);//通过ftok函数得到id值存在key中,下面创建共享内存时会用到

たshmget():

共有メモリを作成します

int shmget(key_t key, size_t size, int shmflg); //成功返回共享内存的ID,出错返回-1

アプリケーション例:

int shmid = shmget(key, 100, IPC_CREAT | IPC_EXCL | 0666);
//创建共享内存,成功返回共享内存的ID,出错返回-1,IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的共享内存,如果共享内存已存在,返回一个错误。

(1)最初の引数は鍵長整数(唯一の非ゼロ)であり、値を指定する必要がありID IPCシステムは、通信(メッセージキュー、セマフォ、共有メモリ)を確立します。典型的には、カーネルにftok ID機能識別子によって得られた値は、信号の同じセットを取得するために2つの処理を参照して、同じキーの値のみを設定することができます。

(2)第2のサイズパラメータは、共有メモリのサイズを指定し、その値は、一般のサイズの整数倍である(まだ最大整列し、実際のアプリケーション・サイズを使用することができ、ユーザは唯一独自のあるオペレーティング・システムに達していません)。

(3)第三のパラメータは、新たな共有メモリを作成し、フラグshmflgの集合であるshmflg IPC_CREATフラグがセットされ、共有メモリの存在が開きます。IPC_CREAT | IPC_EXCLが新しい、ユニークな共有メモリを作成することができ、共有メモリがすでに存在する場合、エラーを返します。我々はまた、一般的に、ファイルのアクセス権になります

shmctl():

共有メモリを動作させるために

int shmctl(int shm_id, int cmd, struct shmid_ds *buf); //成功返回0,出错返回-1

(1)最初のパラメータは、shm_idたshmget関数は、共有メモリ識別子を返します。

(2)第二のパラメータ、CMD操作は、それは次の3つの値をとることができる取ることです。    

  • IPC_STATは:関連する共有メモリの現在値と、共有メモリの現在の設定値に関連付けられたデータ構造をするshmid_dsすなわちするshmid_dsカバレッジ値。    

  • IPC_SETは:プロセスは、現在の値に関連付けられている共有メモリを置くのに十分な権限を持っている場合するshmid_ds与えられた値の構造に設定されています    

  • IPC_RMID:共有メモリセグメントを削除します。

(3)第三のパラメータは、buf構造体は、共有メモリ・アクセス・パターンおよび構造へのポインタです。shmid_ds構造体には、少なくとも以下のメンバーが含まれて

struct shmid_ds  
{  
    uid_t shm_perm.uid;  
    uid_t shm_perm.gid;  
    mode_t shm_perm.mode;  
};    

shmat():

共有メモリ・セグメントを作成するための後は、プロセスのアドレス空間に接続します

void *shmat(int shm_id, const void *shm_addr, int shmflg); //成功返回指向共享存储段的指针,出错返回-1

アプリケーション例:

void *pshm = shmat(shmid, 0, 0);//挂接操作,成功返回指向共享存储段的指针,出错返回-1
if (*(int *)pshm == -1) {//查看挂接是否成功如果出错返回-1,报错
    printf("shmat error!\n");
    exit(0);
}

(1)最初のパラメータ、shm_idたshmgetは共有メモリを特定の関数によって返されます。

(2)第二个参数,shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。

(3)第三个参数,shm_flg是一组标志位,通常为0

shmdt():

用于分离操作

int shmdt(const void *shmaddr); //成功返回0,出错返回-1
//addr参数是以前调用shmat时的返回值

二、函数实践

在设计实验中,运用共享内存的四个主要函数shmaget函数,shmat函数,shmdt函数,shmctl函数之后,读出传送数据的文件可以视为服务器read.c,传送数据相当于客户端文件write.c,实现进程之间的相互通信。

write.c程序段(将数据写入共享空间):

//write.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <signal.h>
struct Msg {
    int flag;//0为读,1为写
    char content[104];
};
int shmid;
void *pshm;
void Handle(int s) {//监听函数
    if (s == 2)
    {
        shmdt(pshm);
        shmctl(shmid, IPC_RMID, 0);
        exit(0);
    }
}
int main() {
    signal(2, Handle);//按ctrl+c键退出时会处理这个消息,进行共享内存卸载、删除操作,最后exit(0)退出程序

    key_t key = ftok(".", 2);//通过ftok函数得到id值存在key中

    shmid = shmget(key, 100, IPC_CREAT | IPC_EXCL | 0666);/*创建共享内存,成功返回共享内存的ID,出错返回-1,IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的共享内存,如果共享内存已存在,返回一个错误。*/

    pshm = shmat(shmid, 0, 0);//挂接操作,成功返回指向共享存储段的指针,出错返回-1

    if (*(int *)pshm == -1) {//查看挂接是否成功如果出错返回-1,报错
        printf("shmat error!\n");
        exit(0);
    }
    memset(pshm, 0, 100);//初始化
    struct Msg *msg = (struct Msg *)pshm;
    msg->flag = 1;
    while (1) {
        if (msg->flag == 1) {//当为1时写消息,此时读文件中不能操作此共享内存
            printf("请输入内容至共享内存:");
            scanf("%s", msg->content);
            msg->flag = 0;//当写消息后flag置为0,让读文件开始执行读操作,此时写文件不能进行写操作
        }
        else {
            sleep(1);
        }
    }
    return 0;
}

read.c程序段(将数据同步从共享空间读出):

//read.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <signal.h> 
struct Msg {
    int flag;
    char content[104];
};
int main() {

    key_t key = ftok(".", 2);
    int shmid = shmget(key, 0, 0);//通过ftok函数得到id值存在key中

    void *pshm = shmat(shmid, 0, 0);//挂接操作,成功返回指向共享存储段的指针,出错返回-1

    if (*(int *)pshm == -1) {//查看挂接是否成功如果出错返回-1,报错
        printf("shmat error!\n");
        exit(0);
    }

    struct Msg * msg = (struct Msg *)pshm;
    while (1) {
        if (msg->flag == 0) {//当为0时读消息,此时写文件中不能操作此共享内存
            printf("从共享内存收到 : %s\n", msg->content);
            msg->flag = 1;
        }
        else {
            sleep(1);
        }
    }

    return 0;
}

运行结果与分析:

在程序运行中,同时打开两个终端,分别运行write和read程序,便能发现write将内容写入共享内存,而同时read进程自行同步将共享内存中的数据读出,进而实现进程通信 。

设计的这个实验的优点是方便简单,效率非常的高,有着很高的灵活性。但若有多个进程同时读取,可能会出现错误,解决该问题需要有一种进程同步的机制,或者借助其他手段来进行进程间的同步工作,将在接下来的学习中会进一步解决。

三、参考博客与资料

sky_Mata 的 进程间通信方式——共享内存: https://blog.csdn.net/skyroben/article/details/72625028
清清飞扬 的 linux ftok()函数: https://www.cnblogs.com/joeblackzqq/archive/2011/05/31/2065161.html

おすすめ

転載: www.cnblogs.com/huakui/p/11563584.html