• 进程间通信(IPC)


    1.什么是进程间通信

      通俗来讲,进程间通信就是:多个进程之间的数据交互

      进程都有自己独立的虚拟地址空间,导致进程之间的数据交互变得十分困难,通信复杂了,但是安全性提高了;

      进程间通信的本质:多个进程之间是否可以访问同一块内存/缓冲区

      命令:ipcs:显示IPC信息   ipcrm:手动删除IPC资源

    2.进程间通信的目的

      数据传输:一个进程在某些情况下需要将自己的数据发送给另一个进程

      资源共享:多个进程之间共享同样的资源

      通知事件:一个进程可能向其他进程或进程组发送消息,表示发生了某个事件(如进程终止时会向父进程发送SIGCHILD信号)

      进程控制:有些进程,例如DUBUG进程,希望完全控制另一个进程的执行,及时知道进程的状态改变

    3.进程间通信的方式

      1)管道:内核中的一块缓冲区,用于传输数据资源

        匿名管道:内核开辟这段缓冲区的时候没有任何标记,操作系统只返回了该缓冲区的文件描述符供进程使用,对于其他进程,不知道这个文件描述,因此无法发问到这个缓冲区,

      但是对于fork出来的子进程,由于子进程复制了父进程的程序地址空间,因此也复制了该缓冲区的文件描述符,也就意味着子进程可以和父进程进行数据传输,进行通信;

        匿名管道的特点:只能用于具有亲缘关系的进程间通信单向通信(半双工)面向字节流

        int pipe(int fd[2]);    //用于创建匿名管道

        参数:fd是文件描述符数组,其中放到fd[0]表示读端,fd[1]表示写端

          因为管道是单向通信,所以操作系统无法决定到底是读还是写,所以返回两个文件描述符,一个用于读,一个用于写,这样一来,进程对管道是读还是写将由用户决定

        选择读则关闭写,选择写则关闭读

        命名管道:一类特殊的文件,可以用于同一机器上的所有进程之间的通信,拥有匿名管道的所有特性,但是命名管道需要用户自己打开文件;

          创建命名管道:

            命令行创建:mkfifo [filename]

            int mkfifo(const char* filename, mode_t mode)

            第一个参数:管道文件名称,第二个参数文件访问权限

          命名管道和匿名管道的区别:打开方式不同,命名管道需要自己调用open打开,但匿名管道在调用pipe后,自动打开;

          命名管道的打开规则:

            当以读的方式打开命名管道时,阻塞知道有进程以写的方式打开文件;同样的如果以写的方式打开命名管道,则会阻塞知道有进程以写的方式打开

      2)消息队列

        操作系统内核中的队列,传输的是数据块,这个数据块是有类型的

        操作系统为消息队列维护了一个结构体,这个结构体中有两个指针,msg_first与msg_last,分别指向消息队列的首部和尾部

        消息队列函数:

          int msgget(key_t key, int msgflg);

          功能:用来创建和访问一个消息队列

          参数:第一个参数,某个消息队列的名字,第二个参数,权限,类似于文件的权限

          返回值:成功返回消息队列的标识码(非负整数),失败返回-1;

          int msgctl(int msgqid, int cmd, struct msqid_ds *buf);

          参数:第一个参数:由msgget函数返回的消息队列标识码,cmd:将要采取的动作(IPC_STAT, IPC_SET,IPC_RMID)

          返回值:成功返回0,失败返回-1

          msgsnd:此函数的作用,将一条消息添加到消息队列中

          msgrcv:此函数表示将要从一个消息队列中接收消息

      3)共享内存

        进程间通信最快的一种方式,共享内存是在物理内存中开辟一段空间,映射到自己的虚拟地址空间,如果多个进程都进行了映射,则这些进程可以通过共享内存进行通信

      实现数据共享

        因为共享内存是直接对映射到虚拟地址的物理地址进行操作,少了两步由用户空间到内核空间,再由内核空间到用户空间数据的拷贝过程,因此是最快的

        共享内存的函数:

          shmget:用来创建共享内存

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

            参数:key:共享内存段的名字,size:共享内存的大小,shmflg:权限

          shmat:将共享内存段连接到进程地址空间

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

            参数:shmid:共享内存标识 shmaddr:指定连接地址,通常置为NULL,shmflg:SHM_RND SHM_RDONLY(只读)

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

          shmdt:解除映射关系,将共享内存与当前进程脱离

            int shmdt(const void* shmaddr);

            参数:由shmat返回的指针

          shmctl:用于控制共享内存

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

            参数:shmid为由shmget返回的共享内存表示码;cmd为将要采取的动作;buf:指向一个保存着共享内存模式状态和访问权限的数据结构

        共享内存的操作步骤:

          1.创建共享内存

          2.将内存空间映射到虚拟地址空间

          3.通过虚拟地址对内存进行操作

          4.接触虚拟地址空间中的映射关系

          5.删除共享内存

          6.查看共享内存:ipcs -m

          7.删除共享内存:ipcrm -mid

          8.共享内存的使命周期随内核

      4)信号量

        信号量=计数器+等待队列

        信号量这个计数器实际就说明现在是否可以访问资源,及表明当前有多少资源,信号量<0,表明需要等待,当有资源时唤醒等待,再进行操作

        信号量的PV原语

          互斥:P、V在同一进程中

          同步:P、V在不同进程中

        

      

  • 相关阅读:
    Python assert(断言)
    Python importlib(动态导入模块)
    Python 异常处理
    Qt Clipboard剪贴板简单使用
    Qt5 QTableWidget设置列表自动适应列宽
    Fix VNC Desktop Sharing on Ubuntu Desktop 14.04
    Golang 交叉编译
    stdobj to array php
    Elasticsearch-集群原理
    Elasticsearch-基本操作2
  • 原文地址:https://www.cnblogs.com/love-you1314/p/10496984.html
Copyright © 2020-2023  润新知