进程间通信(共享内存)

共享内存的概念:<没有同步与互斥机制,生命周期随内核>
共享内存就是两个或多个进程占有一段内存空间,同一块物理内存空间被映射到两个进程,两个进程都可以访问这段共享空间,从而实现了进程间通信,但其只有数据交换的功能,并没有提供同步与互斥机制。
共享内存是最快的ipc形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不涉及到内核。
共享内存区进程间的数据传递:
(1).用户空间到内存。
(2).内存到用户空间。

下图是共享内存的结构:
这里写图片描述

共享内存的数据结构:

struct shmid_ds{
    struct ipc_perm  shm_perm;//IPC对象数据结构 
    int             shm_segsz;//共享内存的字节数
    _kernel_time_t  shm_atime;//最后一次映射的时间
    _kernel_time_t  shm_dtime;//最后一次脱离的时间
    _kernel_time_t  shm_ctime; //最后一次更动此共享内存的时间。 
    _kernel_ipc_pid_t shm_cpid; // 建立此共享内存的进程识别码。
    _kernel_ipc_pid_t shm_lpid;// 最后一个操作此共享内存的进程识别码。
    unsigned short     shm_nttach; /* no. of current attaches */ 
    unsigned short     shm_unused;/* compatibility */ 
    void  *shm_unused2;/* ditto - used by DIPC */ 
    void  *shm_unused3;/* unused */ 
    };

共享内存函数:
shmget函数:
功能:用来创建共享内存。
函数原型:

int shmget(key_t key,size_t size,int shmflg);

参数:

  1. key:共享内存段的名字。
  2. size:共享内存的大小。
  3. shmflg:由9个权限标志组成,它们的用法和创建文件时使用的mode 模式标志是一样的。

返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1。

shmat函数:
功能:将共享内存段连接到进程地址空间。
原型:

    void *shmat(int shmid,const void *shmaddr,int shmflg);

参数:

  1. shmid:共享内存标识
  2. shmaddr:指定连接的地址
  3. shmflg:取值为SHM_RND和SHM_RONLY

返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1.

说明:

 1. shmaddr为NULL,核心自动选择一个地址。
 2. shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
 3. shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。
公式:shmaddr-(shmaddr%SHMLBA)
 4.shmflg=SHM_RONLY,表示连接操作用来只读共享内存。

shmdt函数:
功能:将共享内存段与当前进程脱离。
原型:

       int shmdt(const void *shmaddr);

参数:
shmaddr:由shmat返回的指针。
返回值:成功返回0,失败返回-1.
将共享内存段与当前进程脱离不等于删除共享内存段
shmctl函数:

       #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmctl(int shmid, int cmd, struct shmid_ds *buf);

返回值:如果操作成功返回0,否则返回-1。

各参数的含义如下:

(1)参数shmid

参数shmid表示需要操作的共享内存标识符,也就是shmget函数的返回值。

(2)、参数cmd

参数cmd指明了所要进行的操作类型,主要有以下五种:

cmd取值 操作类型
IPC_STAT 取该共享内存的shmid_ds结构,并存在第三个参数中
IPC_SET 使用buf指定的结构设置相关属性
IPC_RMID 删除指定共享内存,只有当buf中的shm_nattch值为0时才真正删除
IPC_LOCK 在内存中对共享内存加锁(超级用户权限)
IPC_UNLOCK 解锁共享内存(超级用户权限)

参数buf:指向一个保存着共享内存的模式状态和访问权限的数据结构。

具体代码实现如下:
common.h

  1 #pragma once
  2 #include<stdio.h>
  3 #include<sys/ipc.h>
  4 #include<sys/shm.h>
  5 #include<sys/types.h>
  6 
  7 #define PATHNAME "."
  8 #define PROJ_ID 0x6666
  9 
 10 int commonshm(int size,int flags);
 11 int createshm(int size);
 12 int getshm(int size);
 13 int destoryshm(int shmid);

common.c

#include"common.h"
  2 int commonshm(int size,int flags)
  3 {
  4         key_t key=ftok(PATHNAME,PROJ_ID);
  5         if(key<0){
  6                 perror("ftok()");
  7                 return -1;
  8         }
  9         int shmid=shmget(key,size,flags);
 10         if(shmid<0){
 11                 perror("shmget()");
 12         }
 13         return shmid;
 14 }
 15 int createshm(int size)
 16 {
 17         return commonshm(size,IPC_CREAT|IPC_EXCL|0666);
 18 }
 19 int getshm(int size)
 20 {
 21         return commonshm(size,IPC_CREAT);
 22 }
 23 int destoryshm(int shmid)

server.c:

  1 #include"common.h"
  2 int main()
  3 {
  4         int shmid=createshm(1024);
  5         char*ptr=(char*)shmat(shmid,NULL,0);
  6         int i=0;
  7         while(1){
  8                 printf("client# %s\n",ptr);
  9                 ptr[i]='A';
 10                 ptr[++i]='\0';
 11                 sleep(1);
 12         sleep(1);
 13         }
 14         shmdt(ptr);
 15         sleep(1);
 16         destroyshm(shmid);
 17         return 0;
 18 }

client.c

#include"common.h"
  2 int main()
  3 {
  4         int shmid=getshm(1024);
  5         char*ptr=(char*)shmat(shmid,NULL,0);
  6         int offset=0;
  7         //while(1){
  8         //      printf("server# %s\n",ptr);}
  9         while(1){
 10                 printf("server# %s\n",ptr);
 11                 int count=0;
 12                 char*cur=ptr;
 13                 for(;count<10;++count){
 14                         *cur++='A'+offset;
 15                         sleep(1);
 16                 }
 17                 *cur='\0';
 18                 ++offset;
 19                 offset%=26;
 20         }
 21         sleep(1);
 22         shmdt(ptr);
 23         return 0;
 24   }

这里写图片描述
因为共享内存没有同步与互斥机制,若要实现双向通信。则需用两个共享内存区。
如:A->B,A只能写数据,B只能读数据。
B->A,B只能写数据,A只能读数据。

这里写图片描述

猜你喜欢

转载自blog.csdn.net/xiaodu655/article/details/80199843
今日推荐