linux进程通信----共享内存

来源:互联网 发布:知乎立升净水器好不好 编辑:程序博客网 时间:2024/05/17 07:31

共享内存是一种最为高效的进程间通信方式,因为进程可以直接读写内存,不需要任何数据的复制,为了在多个进程间交换信息,内核专门留出了一块内存区,这块内存进程可以直接将其映射到进程的私有空间中,可以直接读写,所以大大提高了效率,由于多个进程共享一个内存区,所以需要依靠某种同步机制,例如信号量,互斥锁等。

共享内存原理示意图:

实现共享内存有三个步骤:

  1. 创建共享内存,使用shmget(),也就是从内存中获取一段共享内存区域
  2. 映射共享内存,把创建的共享内存映射到具体的进程空间中,使用函数shmat(),现在就可以使用共享内存了,可以使用不带缓冲的的I/O读写命令对其进行操作
  3. 撤销映射的操作,使用shmdt()函数即可

shmget()的函数语法格式:

shmat()函数语法如下:

shmdt语法如下:

这里需要补充一个删除共享内存的函数shmctl()

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#define BUFFER_SIZE 2048int main(){    pid_t pid ;    int shmid ;    char *shm_addr ;    char flag[] = "WROTE" ;    char *buff ;    //创建共享内存    if ((shmid = shmget(IPC_PRIVATE, BUFFER_SIZE, 0666)) < 0)    {        perror("shmget") ;        exit(1) ;    }    else    {        printf("create shared-memory:%d\n", shmid) ;    }    system("ipcs -m") ;//通过ipcs -m获取共享内存的信息    pid = fork() ;    if (pid == -1)    {        perror("fork") ;        exit(1) ;    }    else if (pid == 0)    {    //shm_addr是传回来的映射地址,判断其是否等于(void *)-1???        if ((shm_addr = shmat(shmid, 0, 0)) == (void *)-1)        {            perror("child:shmat") ;            exit (1) ;        }        else        {            printf("child:attach shared memeory:%p\n", shm_addr) ;        }        system("ipcs -m") ;//子进程映射之后查看共享内存的状态        /*通过查看共享内存是否含有flag,如果有表示父进程已经向共享内存中        写入了数据,以此做了一个简单的同步的工作*/        while(strncmp(shm_addr, flag, strlen(flag)))        {            printf("child:wait for enable data...\n") ;            sleep(5) ;        }        strcpy(buff, shm_addr + strlen(flag)) ;        printf("child:shared-memory:%s\n", buff) ;        if ((shmdt(shm_addr)) < 0)//撤销映射        {            perror("shmdt") ;            exit(1) ;        }        else        {            printf("child:deattach shared-memory\n") ;        }        system("ipcs -m") ;//撤销映射之后共享内存的状态        if (shmctl(shmid, IPC_RMID, NULL) == -1)//删除共享内存        {            perror("shmctl") ;            exit(1) ;        }        else        {            printf("delete shared-memory\n") ;        }        system("ipcs -m") ;//删除共享内存之后,查看共享内存的状态    }    else    {        if ((shm_addr = shmat(shmid, 0, 0)) == (void *) - 1)//父进程映射内存        {            perror("shmat") ;            exit(1) ;        }        else        {            printf("parent: attach shared-memory:%p\n", shm_addr) ;        }        sleep(1) ;        printf("\ninput some string\n") ;        fgets(buff, BUFFER_SIZE, stdin) ;//从标准输入中提取BUFFER_SIZE个字符        strncpy(shm_addr + strlen(flag), buff, strlen(buff)) ;//向共享内存中写入        strncpy(shm_addr, flag, strlen(flag)) ;        if (shmdt(shm_addr) < 0)//解除映射        {            perror("shmdt") ;            exit(1) ;        }        else        {            printf("deatch shared-memory\n") ;        }        system("ipcs -m") ;        waitpid(pid, NULL, 0) ;//等待子进程结束        printf("finished\n") ;    }    exit(0) ;}
创建共享内存时我们指定键值为IPC_PRIVATE,用于创建当前进程的私有共享内存,这个例子中创建的共享内存是父子进程之间的共用部分,所以指定了IPC_PRIVATE

可以看一下运行结果:

在创建共享内存时:

父子进程分别作了映射:

此时看共享内存的状态:

然后我们向共享内存输入一个字符串"zhang",子进程将会读出这个字符串,然后父子进程分别解除映射

最后子进程删除共享内存,此时将查看不到共享内存.

因为共享内存是这里使用一个标志字符串作为同步的标志

这里有个问题弄不懂:

共享内存需要互斥访问,父子进程是怎么同步的?

子进程:
   while(strncmp(shm_addr, flag, strlen(flag)))   {      printf("child:wait for enable data...\n") ;      sleep(5) ;   }

父进程:

 printf("\ninput some string\n") ; fgets(buff, BUFFER_SIZE, stdin) ;//从标准输入中提取BUFFER_SIZE个字符 strncpy(shm_addr + strlen(flag), buff, strlen(buff)) ;//向共享内存中写入 strncpy(shm_addr, flag, strlen(flag)) ;
父子进程都对共享内存进行了操作,那怎么互斥访问呢?




原创粉丝点击