리눅스 프로세스 간 통신 ④ - 공유 메모리(Shared Memory)

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

추천

출처blog.csdn.net/xll102500/article/details/129564341