【Linux】system V进程间通信--共享内存,消息队列,信号量

发布于:2024-10-17 ⋅ 阅读:(5) ⋅ 点赞:(0)

目录

共享内存

基本原理

创建共享内存

共享内存创建好后,我们可以查询共享内存,验证一下是否创建成功;

删除共享内存

共享内存的挂接

实现通信

消息队列(了解)

消息队列概念

消息队列接口

操作指令

信号量(了解)

信号量概念

理解信号量

信号量操作


通信的方式有三种:聚焦本地通信的System V,实现跨主机之间的通信POSIX,以及基于文件系统的管道通信

下面是System V的通信方式:

system V IPC提供的通信方式有三种: 共享内存、消息队列、信号量;并且生命周期是随OS的,而不是随进程的,这是所有System V进程间通信的共性;

共享内存

共享内存=内存空间(数据)+共享内存的属性!!!

基本原理

共享内存:通过让不同的进程,看到通过一个内存块的方式就叫共享内存;

我们把创建好的内存称为共享内存;进程和共享内存建立映射关系称为挂接;取消进程和共享内存的映射关系称为释放内存空间;

  • 创建共享内存

这里我们用的是shmget来创建共享内存;

size:要创建的共享内存的大小;

shmflg:标识符,IPC_CREAT ,IPC_EXCL;

  1. IPC_CREAT:如果创建的shm不存在,则创建;反之,则获取该内存并返回(总能获取一个shm);
  2. IPC_EXCL:单独使用没有意义;
  3. IPC_CREAT | IPC_EXCL:如果创建的shm不存在,则创建;反之,则出错返回;(意味着shm是全新的);

key:用户形成(唯一性的);保证看到同一份共享内存,能进行唯一性标识。如何形成?ftok

  • pathname:路径
  • proj_id:标识符

创建共享内存要先创建出key,在创建内存:

  1. key_t key = ftok(_path.c_str(), _proj_id);
            if (key < 0)
            {
                perror("ftok");
            }
            return key;
  2. int Shmget(key_t key,int size, int flag)
        {
            int shmid = shmget(key, size, flag);
            if (shmid < 0)
            {
                perror("shmget");
            }
            return shmid;
        }

共享内存创建好后,我们可以查询共享内存,验证一下是否创建成功;

查询共享内存:ipcs -m

删除共享内存

 删除共享内存:ipcrm -m +shmid

shmid:创建共享内存的返回值;

cmd:通常为IPC_RMID;

buf:用于存储共享内存的信息;

key VS shmid

  • key:用户形成,内核使用的一个字段,用户不能使用key来进行shm的管理,内核进行区分shm的唯一性的(类比于struct file来理解);
  • shmid:内核给用户返回的一个标识符,用来进行用户级对共享内存进行管理的id值(类比于fd来理解);

共享内存的挂接

  • shmat:关联共享内存
  • shmdt:去关联

shmaddr:指定虚拟地址,但是我们并不了解,直接设置为nullptr即可;shmflg:读取权限,默认为0

  1.     void *Attachshm()
        {
            void * shmaddr=shmat(_shmid,nullptr,0);
            if(shmaddr==nullptr)
            {
                perror("shmat");
            }
            cout<<"who: "<<_who<<"   attach shm..."<<endl;
            return shmaddr;
        }
  2. void deleteshm(void * shmaddr)
        {
            if(shmaddr==nullptr)return ;
            int res = shmdt(shmaddr); 
        }

这样我们就完成的通信前的准备工作;

实现通信

我们把准备工作完成后,通信过程就比较简单了;因为共享内存是一段内存,我们在访问一个内存时,如果权限够的话,可以直接进行读取和写入;

不管我们运行代码时会发现一个问题就是我们的内容还没有写完,就会被读取;这是因为共享内存不提供对共享内存的任何保护机制  ----->数据不一致问题;

怎么解决这个问题???

我们只需要引入管道即可解决;

共享内存是所有进程间通信速度是最快的,因为共享内存是被双方所共享,只要写入对方就能立即看到,能大大减少数据的拷贝次数。

消息队列(了解)

消息队列概念

        消息队列是OS提供的内核级队列,消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法,每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

消息队列接口

  • msgget:获取消息队列

  • msgctl:控制消息队列

  • msgsnd:发送消息
  • msgrcv:读取消息

操作指令

ipcs -q

ipcrm -q +msgid

信号量(了解)

信号量概念

理解信号量

信号量、信号灯  ------->保护临界资源(code)

类比于去电影院看电影,人们必须要买票才能进去看电影;

  • 电影院:共享资源(临界资源);
  • 买票:申请信号量;
  • 票数:信号量的初始值;

申请信号量本质 就是对公共资源的预定机制;

信号量的本质是一个计数器,通常用来表示公共资源中,资源数的多少问题。信号量主要用于同步和互斥的。

既然信号量本质是一个计数器,那么可以用一个全局变量来代替吗?

不行,全局变量不能让所有进程都能看到,而且count++/count--不是原子的;

信号量操作

  • semget:申请信号量

  1. nsems:申请信号量的个数
  2. semflg:IPC_CREAT ,IPC_EXCL;

  • semctl:删除信号量

  1. semid:semget的返回值;

  • semop:信号量操作


网站公告

今日签到

点亮在社区的每一天
去签到