一、共享内存
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