Linux进程间通讯(2)——共享内存

五迷三道 提交于 2020-03-17 01:52:03

共享内存

  1. 共享内存是进程间通讯最简单最快速的方式

  2. 访问共享内存区域和访问进程独有的内存区域一样快,并不需要通过系统调用或者其他需要切入内核的过程来完成。同时也避免了对数据的各种不必要的复制。

  3. 使用步骤:
    (1)首先要分配一块共享内存,使用shmget函数
    函数定义:int shmget(key_t key,size_t size, int shmflg);

    第一个参数——由程序提供一个key,为创建的共享内存段命名,shmget()函数成功时返回一 个与key相关的共享内存标识符,若调用失败则返回1。不相关的进程可以通过该函数的返回值访问 共享内存。

    第二个参数——size是要建立共享内存的长度

    第三个参数——shmflg是权限标志,比如IPC_CREAT和IPC_EXCL,它们的功能与open()中的O_CREAT和O_EXCL一样。通常情况下我们会使用0644|IPC_CREAT来作为shmflg的值。

    (2)要访问这个共享内存块的每一个进程都必须将这个共享内存绑定到自己的地址空间中,我们使用shmat函数
    函数定义:char *shmat(int sh_mid,char*shm_addr,int flag);

    第一个参数——shmid是由shmget()函数返回的内存共享标识。

    第二个参数——shmaddr指定共享内存连接到当前进程中的地址位置,通常为NULL,让系统来安排共享内存的地址。

    第三个参数——shmflg是一组标志位,通常为0。

    返回值——如果成功则返回共享内存映射到进程中的地址;如果失败则返回-1。

    (3)通信完毕后,全部进程都将脱离共享内存,使用shmdt函数
    函数定义:int shmdt(char *shmaddr);

    该函数作用是将共享内存从当前进程中分离开来,并不是将它删除,只是使当前进程对共享内存没有使用的能力。

    参数shmaddr是shmat()函数返回的地址指针,调用成功返回0;如果失败返回-1。

    (4)最后释放该内存块,使用shmctl函数
    函数定义:int shmctl(int sh_mid,int command,struct shmid_ds *buf);

    第一个参数——shmid是shmget()函数返回的共享标识符。

    第二个参数——command是要采取的操作,例如:

    IPC_STAT:用共享内存的当前关联值覆盖shmidds的值。
    IPC_SET:把共享内存的当前关联值设置为shmidds结构中的给出的值
    IPC_RMID:删除共享内存段
    

    第三个参数,buf是一个结构指针,他指向共享内存模式和访问权限的结构

父子进程共享内存

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

typedef struct{
    char dat[100];
}SM;

int main(){
    SM *smp;
    printf("size:%d\n",sizeof(SM));
    int shmid = shmget(1,sizeof(SM),0644|IPC_CREAT);

    if(shmid ==-1){
        perror("shmget, error!");
        exit(1);
    }

    smp = shmat(shmid,NULL,0);//将返回的地址赋给smp
    if(smp==(void*)-1){//(void*)将-1转换为地址与smp进行比较
       perror("shmat error!");
       exit(1);
    }
    printf("share memry successful!\n");

    pid_t pid = fork();

    if(pid < 0){
         perror("fork error!");
         exit(1);
         //子进程read
    }else if(pid == 0){ 
         while(1){
          	 if(strlen(smp->dat)==0){
                    sleep(1);
                    continue;
              }
        	printf("receive:%s\n",smp->dat);

              if(strcmp(smp->dat,"exit")==0){
                       break;
                }
               memset(smp,0,sizeof(SM));
        }
        if(shmdt(smp)==-1){
                perror("shmdt error!");
                exit(1);
        }
        if(shmctl(shmid,IPC_RMID,NULL)==-1){
                perror("shmctl error!");
                exit(1);
        }
        printf("remove shm successfully\n");
        //父进程write
    }else if(pid > 0){
         while(1){
             scanf("%s",smp->dat);
             if(strcmp(smp->dat,"exit")==0){
                break;
             }
         }
        if(shmdt(smp)==-1){
                perror("shmdt error!");
                exit(1);
        }
        sleep(3);
    }
    return 0;
}


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!