1. 공유 메모리
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는 권한 플래그 , 파일을 읽고 쓰는 것과 동일하며 존재하지 않는 키로 식별되는 공유 메모리를 생성하려면 IPC_CREAT로 OR 연산을 하면 됨 ③ 함수 반환 값: 성공, 음이 아닌 값 반환 정수, 즉
공유 메모리 메모리 세그먼트의 식별 코드 실패 시 -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은 시스템이 공유 메모리의 주소를 선택하도록 함을 의미
합니다
. 함수의 : 성공하면 공유 메모리의 첫 번째 바이트에 대한 포인터를 반환하고 실패하면 -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 반환
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