Linuxのプロセス間通信④ - 共有メモリ(Shared Memory)

1. 共有メモリ

1.1 基本的な概要

共有メモリは、プロセス間で通信する最も簡単な方法の 1 つです。共有メモリとは、2 つ以上のプロセスが同じメモリ空間にアクセスできることを意味します。プロセスがこの空間のメモリを変更すると、通信中の他のメモリはその変更を認識します。 。
共有メモリ領域はプロセス間通信の最速の形式です

1.2 機能の紹介

1.2.1 シュムゲット()

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key,size_t size,int shmflg);

①関数関数: 共有メモリの作成
②関数パラメータ:
第一引数→keyはfork()が返すkey_t型のキー値、第
二引数→sizeは共有するメモリ容量をバイト単位で指定、
第三引数→shmflgは許可フラグファイルの読み書きと同じです キーで識別される共有メモリが存在しない場合に作成したい場合は、IPC_CREATとのOR演算を行うことができます ③ 関数の戻り値:success、非負の値を返します整数、つまり
共有メモリ メモリセグメントの識別コード; 失敗した場合は -1 を返します。

1.2.2 shmat()

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid,const void *shmaddr,int shmflg);

①関数関数: 作成された共有メモリへのアクセスを開始し、共有メモリを現在のプロセスのアドレス空間に接続します;
②関数パラメータ:
最初のパラメータ→ shmid は shmget() 関数によって返される共有メモリ識別子です;
2 番目のパラメータ→shmadr は、共有メモリが現在のプロセスに接続されているアドレスを指定します (通常は NULL、システムに共有メモリのアドレスを選択させることを意味します); 3 番目のパラメータ →shmflg はフラグ ビットのセットで、通常は 0; ③
戻り
値関数の: 成功した場合は共有メモリの最初のバイトへのポインタを返し、失敗した場合は -1 を返します。

1.2.3 shmdt()

#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);

①関数 function : 現在のプロセスから共有メモリを分離します (共有メモリの分離は、共有メモリを削除することではなく、共有メモリを現在のプロセスが利用できなくすることです); ②関数パラメータ: パラメータ shmaddr は、関数によって返されるアドレス ポインタ
です。 shmat関数;
③ 関数の戻り値: 成功、戻り値 0; 失敗、戻り値 -1;

1.2.4 shmctl()

#include <sys/types.h>
#include <sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);

①関数 function : 共有メモリの制御に使用されます。 ②関数
パラメータ:
最初のパラメータ→ shmid は shmget() 関数によって返される共有メモリ識別子です。
2 番目のパラメータ→ cmd は実行される操作であり、次の 3 つの値を取ることができます。

IPC_STAT: shmid_ds 構造体のデータを共有メモリの現在関連付けられている値として設定します。つまり、shmid_ds のログを共有メモリの現在関連付けられている値で上書きします。 IPC_SET: プロセスに十分な権限がある場合は、現在関連付けられている値を設定します
。共有メモリの値を shmid_ds
IPC_RMID: 共有メモリ セグメントを削除

3 番目のパラメータ→buf は、共有メモリ モードとアクセス権の構造体を指す構造体ポインタであり、その構造体の型は次のように定義されます。

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

③関数の戻り値:成功時は0を返し、失敗時は-1を返します。

1.3 共有メモリプログラミング

クライアントは 10 秒ごとに共有メモリに温度を書き込み、サーバーはこの共有メモリからデータを読み取ります

1.3.1 サーバーコード

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>

#define LEN   1024
#define FTOK_PATH   "/dev/zero"
#define FTOK_PROJID     0x22

typedef struct shared_use_st
{
    
    
    int written;	//作为可读可写标志,written =0 ,可写,非0为可读
    char T[LEN];	//写入、读取的内容
}shared_use;
int main(int argc,char **argv)
{
    
    
    void *shm = NULL;
    shared_use  *shared;
    int shmid;	//共享内存标识符
    key_t key;	

    if((key = ftok(FTOK_PATH,FTOK_PROJID)) < 0)
    {
    
       
        printf("ftok() get key failure:%s\n",strerror(errno));
        return -1; 
    }   
    shmid = shmget(key,sizeof(shared_use),IPC_CREAT | 0666);	//创建共享内存
    if(shmid < 0)
    {
    
       
        printf("shmget() creat shared memroy failure:%s\n",strerror(errno));
        return -1; 
    }   
    printf("get key_t[0x%x] and shmid[%d]\n",key,shmid);


    shared = shmat(shmid,NULL,0);	//将共享内存连接到当前进程的地址空间
    if((void *) -1 == shared)
    {
    
    
        printf("shmat() alloc shared memroy failure:%s\n",strerror(errno));
        return -1;
    }

    shared ->written = 0;
    while(1)		//读取共享内存中的数据
    {
    
    
        if(shared -> written == 1)	//没有进程向内存写数据,则有数据可读
        {
    
    
            printf("the data form shared memroy:%s\n",shared ->T);
            sleep(1);
            shared ->written = 0;		//读完数据,设置其为共享内存段可写
        }
        else				//有其他进程在写数据 ,不能读取数据
        {
    
    
            sleep(1);
        }
    }
    if(shmdt(shared)  == -1)		//把共享内存从当前进程中分离
    {
    
    
        printf("shmdt() failure:%s",strerror(errno));
        return -1;
    }
    shmctl(shmid,IPC_RMID,NULL);		//删除共享内存
    return 0;
}

1.3.2 クライアントコード

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <time.h>

#define FTOK_PATH   "/dev/zero"
#define FTOK_PROJID  0x22
#define LEN  1024
typedef struct shared_use_st
{
    
    
    int written;
    char  T[LEN];
}shared_use;

int get_temp(float *temp);
int main(int argc,char **argv)
{
    
    
    float temp;
    char buf[1024];;
    key_t  key;
    int  shmid;
    shared_use  *shared ;
    int rv=0;

  if((key = ftok(FTOK_PATH,FTOK_PROJID)) < 0)
    {
    
    
        printf("ftok() get key failure:%s\n",strerror(errno));
        return -1;
    }
    shmid = shmget(key,sizeof(shared_use),IPC_CREAT | 0666);	//创建共享内存
    if(shmid < 0)
    {
    
    
        printf("shmget() create shared memory failure:%s\n",strerror(errno));
        return -1;
    }
    printf("get key_t[0x%x]  and shmid [%d]\n",key,shmid);

    shared = shmat(shmid,NULL,0);		//将共享内存连接到当前的进程地址空间
    if((void *) -1 == shared)
    {
    
    
        printf("shmat() alloc shared memroy failure:%s\n",strerror(errno));
        return -1;
    }
    rv = get_temp(&temp);
    if(rv<0)
    {
    
    
        printf("get   temperature failure:%s\n",strerror(errno));
        return -1;
    }
    sprintf(buf,"%f\n",temp);
    while(1)			//向共享内存写数据 
    {
    
    
        while(shared->written == 1)		//数据还未被读取,则等待数据被读取
        {
    
    
            sleep(1);
            printf("waiting...\n");
        }
        strcpy(shared->T,buf);			//向共享内存写入数据
        printf("the temperature is:%s\n",shared->T);
        shared->written = 1;			//数据写完,设置为共享内存段可读
    }
        shmdt(shared);			//把共享内存从当前进程中分离
        shmctl(shmid,IPC_RMID,NULL);
        sleep(2);
        return 0;
}

int get_temp(float *temp)			//获取温度
{
    
    
    char    *w1_path = "/sys/bus/w1/devices";
    char    ds_path[50];
    char    chip[20];
    char    buf[1024];
    DIR     *dirp;
    struct  dirent  *direntp;
    int     ds18b20_fd = -1;
    char    *ptr;
    int     found = 0;
    int     ds18b20_rv = 0;

   if((dirp = opendir(w1_path)) == NULL )
    {
    
    
        printf("opendir error: %s\n",strerror(errno));
        return -2;
    }

    while((direntp = readdir(dirp)) != NULL)
    {
    
    
        if(strstr(direntp->d_name,"28-"))
        {
    
    
            strcpy(chip,direntp->d_name);
            found = 1;
            break;
        }
    }
    closedir(dirp);
    if(!found)
    {
    
    
        printf("can not find ds18b20 in %s\n",w1_path);
        return -3;
    }

    snprintf(ds_path,sizeof(ds_path),"%s/%s/w1_slave",w1_path,chip);

    if((ds18b20_fd = open(ds_path,O_RDONLY)) < 0 )
    {
    
    
        printf("open %s error : %s\n",ds_path,strerror(errno));
        return -4;
    }
   if(read(ds18b20_fd,buf,sizeof(buf)) < 0)
    {
    
    
        printf("read %s error:%s\n",ds_path,strerror(errno));
        ds18b20_rv = -5;
        goto cleanup;
    }

    ptr = strstr(buf,"t=");
    if(!ptr)
    {
    
    
        printf("error:can not get temperature\n");
        ds18b20_rv = -7;
        goto cleanup;
    }
    ptr += 2;
    *temp = atof(ptr)/1000;

    snprintf(buf,sizeof(buf),"%f",*temp);

cleanup:
    close(ds18b20_fd);
    return ds18b20_rv;
}

1.3.3 実行結果

//server:
get key_t[0x22050005] and shmid[27]
the data from shared memroy :28.125000

the data from shared memroy :28.125000



//client:
get key_t[0x22050005]  and shmid [27]
the temperature is:28.125000

waiting...
waiting...
the temperature is:28.125000

おすすめ

転載: blog.csdn.net/xll102500/article/details/129564341