Linux之进程间通信④——共享内存(Shared Memory)

一、共享内存

1.1 基本介绍

共享内存是进程间通信最简单的方式之一,共享内存即两个或多个进程可以访问同一个内存空间,当一个进程对这块空间内存进行修改,通信中的其他内存都会察觉到该修改。
共享内存区是最快的进程间通信形式

1.2 函数介绍

1.2.1 shmget()

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

①函数功能:创建共享内存
②函数参数
第一个参数→key为fork()返回的key_t类型键值;
第二个参数→size以字节为单位指定需要共享的内存容量;
第三个参数→shmflg为权限标志,与文件的读写一样,如要想在key标识的共享内存不存在就创建它,可以与IPC_CREAT做或操作
③函数返回值:成功,返回一个非负整数,即该共享内存段的标识码;失败,返回-1;

1.2.2 shmat()

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

①函数功能:启动对创建好的共享内存的访问,并把共享内存连接到当前进程的地址空间;
②函数参数
第一个参数→shmid为shmget()函数返回的共享内存标识;
第二个参数→shmadr指定共享内存连接到当前进程中的地址位置,通常为NULL,表示让系统来选择共享内存的地址;
第三个参数→shmflg为一组标志位,通常为0;
③函数返回值:成功,返回一个指向共享内存第一个字节的指针;失败,返回-1;

1.2.3 shmdt()

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

①函数功能:将共享内存从当前进程中分离(将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用);
②函数参数:参数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);

①函数功能:用于控制共享内存
②函数参数
第一个参数→shmid是shmget()函数返回的共享内存标识符
第二个参数→cmd是要采取的操作,可以取如下三个值:

IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的志;
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds
IPC_RMID:删除共享内存段

第三个参数→buf是一个结构指针,它指向共享内存模式和访问权限的结构,其结构体类型定义如下:

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

③函数返回值:成功,返回0;失败,返回-1;

1.3 共享内存编程

client向一块共享内存每隔10s写入温度,server从这一块共享内存读取数据

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