• 进程间通信


    进程间通信

      基本介绍:

        操作系统提供给用户的几种进程间的通信方式

        进程间通信方式是干什么的:

          进程间数据传输  数据共享  进程控制  事件通知

          正式因为有不同的需求,因此操作系统之间有人提供了多找不同的进程间的通信方式:

            续继承与unix而来的管道(匿名管道/命名管道)  共享内存  消息队列  信号量

        为什么操作系统要给用户提供进程间通信方式:

        进程的独立性导致进程之间没有办法进行通信——由操作系统来提供一个公共的媒介,来进行通信

      通信方式:

        管道:(本质是内存的缓冲区)

          管道创建在内核态,是一个“半双工通信”(提供双向选择但是只能单向传输)。在传输信息时提供io操作——返回文件描述符作为

          句柄(两个文件描述符)一个用于写入数据,另一个用于读数据

        匿名管道/命名管道:

          命名管道:有名字则可以通过名字来打开相同的管道进行通信

          匿名管道没有名字,因此只能通过子进程复制父进程的方式实现通信(复制了文件描述符)

          *匿名管道只能同于具有亲缘关系的进程通信

          *命名管道可以用于任意进程间通信

          

          匿名管道:

            创建匿名管道(在创建子进程之前):

              int pipe(int pipefd[2])

              pipefd[0]——管道的读取端

              pipefd[1]——管道的写入端

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

              读写特性:

                1.管道中若没有数据,则read会阻塞,直到读取数据(由数据被写入管道了)。

                2.管道中若数据满了,则write会阻塞,直到由空闲空间(有数据被读取走了)。

                3.若所有读端被关闭,则wriet会触发异常——SIGPIPE(导致进程退出)

                 若所有写端被关闭,则read读完数据之后不会阻塞,而是返回0

                进程在操作管道的时候如果没有用到某一端,则把这一端关闭

                  管道符 | 的实现:  ps -ef | grep pipe

                    shell  父进程pipe

                    ps   子进程1——>将处理结果打印到标准输出——标准输出重定向

                    grep   子进程2——>循环从标准输入读取数据——标准输入重定向

         命名管道:

          为管道创建了一个管道文件,这个管道文件就是管道的名字(有名字体现在)

          创建名字管道:(本质还是在内核的缓冲区)

            int mkfifo(const char* pathname, mode_t mode)

            pathname——管道我呢见的路劲名

            mode——创建文件的权限

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

          打开特性:

            若管道文件文件没有被写的方式打开,则以只读打开则会阻塞;

          读写特性:

            与匿名管道一样

        管道总结:(管道的本质是内核的一块缓冲区)

    1. 匿名管道只能用与具有亲缘关系的进程间通信/命名管道可以用于任意进程间通信
    2. 管道的读写特性+命名管道的打开特性
    3. 管道是半双工通信——可以选方向的单向通信
    4. 管道的生命周期随进程
    5. 管道提供流式服务:字节流传输。传输数据的形式以字节流的形式(缺点:不能知道数据的间隔,造成数据粘连)
    6. 管道自带同步与互斥功能(读写操作数据大小不超过PIPE_BUF(默认4096)大小,读写操作受保护)
      互斥:对临界资源(公共资源)的同一时间唯一访问性(我操作的时候别人不能操作;不写则读阻塞)
            保证安全
      同步:对临界资源(公共资源)的时序可控性(我操作完了别人才能操作)
                 保证合理
      管道的同步与互斥体现在:管道美没有放数据则读阻塞,放了数据之后换对方阻塞,对方读数据
      (我放了,你才能读——同步);数据往管道中没有放完别人不能读也不能写(互斥)
    7. 命名管道独有的特性:打开特性

      共享内存:(是所有进程间通信方式中最快的一种)

        原理:

          1.多个进程通过将同一块内存映射到自己的虚拟地址空间中,实现对相同的一块物理内存进行操作,
          2.通过这种方式实现多个进程间的数据共享功能
          3.因为共享内存是直接通过虚拟地址操作内存实现共享,相较于其他方式少了两次用户态/内核态之间的数据拷贝

        操作步骤:
          1.创建一块共享内存(一个修改,一个查看)
            key_t ftok(const char* pathname, int proj_id)
              通过文件inode结点号与proj_id生成一个key值
            shmget(key_t key, size_t size, int shmflg)
              key:共享内存标识符
              size:共享内存大小
              shmflg:选项标识
                IPC_CREAT:共享内存不存在则创建,存在则打开
                IPC_EXCL:与IPC_CREAT同用,则共享内存存在时报错
                shm_mode 权限
              返回值:标识符(代码中的操作句柄) 失败:-1
            进程间通信方式的查看:
              ipcs命令:[-m -s ]
                可以查看共享内存(nattch表示有多少个进程与它连接)
            删除共享内存:ipcrm [-m -s -q] shmid
          2.将共享内存映射到虚拟地址空间
            void* shmat(int shmid, const void* shmaddr, int shmflg)
              shmid:创建共享内存,返回句柄
              shmaddr:置空,映射首地址由操作系统分配
              shmflg:映射成功后的操作权限
                SHM_RDONLY: 只读
                0 默认—可读可写
              返回值:映射首地址 失败:(void* )-1

          3.直接对这块内存进行操作

            memcpy...
          4.解除映射关系
            int shmdt(const void* shmaddr)
            shmaddr: 映射首地址
          5.删除共享内存(删除时会检测是否还有进程与内存映射,如果还有则拒绝其他进程的映射)
            int shmctl(int shmid, int cmd, struct shmid_ds* buf)
              shmid: 操作句柄
              cmd: 操作类型
                IPC_RMID: 删除共享内存
              buf: 设置/获取共享内存的信息
          共享内存的删除:
            不会被直接删除,而是会判断映射连接数是否为0,为0则直接删除,不为0,则拒绝后续其他进程
            的后续连接,当映射连接数为0 时自动删除。

      消息队列:(消息队列是可以双向通信,传输的是有类型的数据快)
        通过 msgget 创建一个队列:
          int msgget(key_t key, int msgflg);
          利用 msgsnd 来保证获取的数据类型
        本质:内核中的优先级队列

      信号量:
        本质:内核中的一个计数器,并且带有pcb等待队列

      计数器:数据资源的计数器
        如果获取数据时,先判断计数器是否>0;
          若 > 0,则表示有资源,则可以获取数据,并且资源数据-1;
          若 <= 0,则表示没有资源,则阻塞等待;
          产生数据,直接计数+1,并且唤醒等待的进程(只会唤醒在pcb等待队列上的进程)。

        作用:用于实现进程/线程间的同步与互斥
              信号量实现同步依靠:等待+唤醒
              信号量实现互斥依靠:计数器(只有0/1)+等待+唤醒         

  • 相关阅读:
    目前正在自学python,前几天做了一个比较简单的坦克大战游戏,分享出来,想搞一搞的朋友,可以参考。
    我今天给学习运维而英语不好的各位,提供一些计算机英语,感谢惨绿少年的原文和已经离开身边提供英标部分的小虾大佬,只是为了记录。
    前几天看见pthon自动跳一跳很火,自己也按捺不住寂寞,实现了一把。分享一下。图文详解,如果有问题留言,帮解决。
    day01
    java之jvm篇
    mysql
    leecode刷题——数组篇
    java基础
    python进程和线程
    python I/O编程
  • 原文地址:https://www.cnblogs.com/cuckoo-/p/11105327.html
Copyright © 2020-2023  润新知