1、IPC资源简介

  除了管道、文件、以及信号以外,还有IPC这样一种进程间的通信手段。IPC的含义即就是进程间通信资源,它包含三种资源类型。

  (1)、共享内存;

  (2)、信号量;

  (3)、消息队列;

  使用ipcs可以查看当前系统中IPC资源的情况。

wKiom1ffC4Xj60BXAACNAU8qNpA960.png-wh_50


2、共享内存简介

  共享内存简而言之就是一句话:各个进程都能够共同访问的共享的内存区域。

  进程的特征:高度的独立性和封闭性,它能够直接访问的内存只能是自身所包含的。

  共享内存为了达到多个进程访问的效果,必然是独立于所有进程之外的内存区域。共享内存最终是受到操作系统内核管理。

  进程对于共享内存的操作与管理主要是:

  (1)、申请创建一个共享内存区域(操作系统内核是不可能主动为进程创建共享内存的!),操作系统内核得到申请然后创建。

  (2)、申请使用一个已存在的共享内存区域。

  (3)、申请释放共享内存区域(操作系统内核也是不可能主动释放共享内存区域的!),操作系统内核得到申请然后释放。


3、对于共享内存的编程

(1)、需要使用API : shmget()方法。

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

  key_t其实就是long,key就是关键字,size大小,shmflg表示这块内存区域的标志。

  其返回值为共享内存ID(也就是一个编号)shmid,即就是某一个共享内存区域的唯一标识,该标识又是操作系统内核动态分配的。

代码实现创建一块共享内存

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

int main(void){
    key_t key;
    key = 0xabc00000;
    int ret = shmget(key, 256, IPC_CREAT | IPC_EXCL | 0755);
    if(ret == -1){
        perror("");
        return -1; 
    }   
}

运行结果

wKiom1ffFRTQJ7PUAACGqcBwl4I995.png-wh_50

ipcrm -m shmid:通过命令的方式删除共享内存。

(2)、说明key_t

  i>、key_t是一个long类型,是IPC资源外部约定的key(关键)值,通过key值映射对应的唯一存在的某一个IPC资源。

  ii>、通过key_t的值就能够判断某一个对应的共享内存区域在哪,是否已经创建等等。

  iii>、一个key值只能映射一个共享内存区域,但同时还可以映射一个信号量,而且还能同时映射一个消息队列资源,于是就可以使用一个key值管理三种不同的资源。

(3)、shmget()函数第三个参数的使用细节:

取值
说明
IPC_CREAT
创建一个新的共享内存
IPC_EXCL
判断key对应的共享内存是否已经存在

(4)、key_t值的产生,有两种方式:

  i>、把key值写死;

  ii>、根据文件的inode编号生成。需要调用的API:ftok()方法,该方法是获取指定文件的inode编号在根据第二个参数计算得到最终的一个整型量。

共享内存的获取:使用shmget()方法即可。IPC_EXCL


4、共享内存的使用

  共享内存的使用分为2个小的步骤:i>、建立进程与共享内存的映射关系;ii>、读/写(直接使用指针即可);iii>、如果对于共享内存的使用结束,此时就要断开与共享内存的映射。

  对于第一步来说,需要使用的API:shmat()方法。

  对于第三步来说,需要使用的API:shmdt()方法。

  被映射正在使用共享内存是否此时可以执行删除操作呢?

    :是,虽然可以执行删除操作,却不能将其直接删除掉。而是做了2个操作,i>、将其状态置为dest,ii>、将其key值置为0x00000000,IPC_PRIVATE值。

  当共享内存处于dest(待回收状态),则将其资源设为"私有"(只能将该共享资源分享给其子进程,其它进程无法创建于该资源的使用)。


5、共享内存的控制

 共享内存的控制信息可以通过shmctl()方法获取,会保存在struct_shmid_ds结构体中。

  共享内存的控制主要是shmid_ds,即就是共享内存的控制信息。

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

参数:

shmid:就是要被控制的共享内存的编号。

cmd:看执行什么操作(1、获取共享内存信息;2、设置共享内存信息;3、删除共享内存)。

可用命令说明
IPC_STAT从内核中拷贝获取共享内存信息,将其保存到第三个参数指针所指向的空间
IPC_SET将第三个参数所指向的空间的值设置到内核的共享内存管理数据中
IPC_RMID删除共享内存

6、编程实现

写入共享内存的一方:

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

int createShm(void){
    key_t key = ftok("./tmp", 7);
    int shmid = shmget(key, 256, IPC_CREAT | IPC_EXCL | 0755);

    return shmid;
}

int main(void){
    int shmid = createShm();
    if(shmid == -1){
        perror("");
        return -1;
    }
    char *shmptr = (char *)shmat(shmid, NULL, 0);
    if(shmptr == NULL){
        perror("");
        return -1;
    }

    sprintf(shmptr, "Hello I am writer, write to shm");

    return 0;
}

从共享内存读出的一方:

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

int getShm(void){
    key_t key = ftok("./tmp", 7); 
    return shmget(key, 256, IPC_EXCL | 0755);
}

int main(void){
    int shmid = getShm();
    if(shmid == -1){
        perror("");
        return -1; 
    }   
    char *shmptr = (char *)shmat(shmid, NULL, 0); 
    if(shmptr == NULL){
        perror("");
        return -1; 
    }   
    char buf[80];
    memset(buf, 0, sizeof(buf));
    strncpy(buf, shmptr, 80);
    printf("buf content : %s\n", buf);
    
    return 0;
}

运行结果

wKioL1fgsCXwgK4jAAA4tdIx94c341.png-wh_50

wKioL1fgsJjgSoa3AAAc3S4aSP8895.png-wh_50

共享内存的应用场景

  a) 应用场景:将共享内存视作公告板;

  b) 方式与规则:i>、通常只有少量的进程对其进行写操作,大部分的进程只能进行读操作;

  ii>、独占的写方式,写的时候既不能其它进程写也不能其它进程读。