Linux操作系统:进程间通信

通信基本概念

进程通信与进程独立

进程具有独立性,也就是说多个进程运行时独享自己的资源(数据),互不干扰影响。而进程通信则是数据的交互,这与数据独立似乎有所矛盾,但实际上进程独立也是独立的,进程数据也是可以交互的,进程间也会产生协作关系的。(利用管道文件,或者共享内存)

进程间通信的目的

  • 数据传输:一个进程需要将它的数据发送给另一个进程
  • 资源共享:多个进程之间共享同样的资源。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

进程间通信的分类

想要让两个进程通信,就要用尽一切方法让他们看见同一份内存空间

当使用fork函数时,子进程会将父进程作为模板,拷贝父进程的数据,所以当父进程打开文件,它就有了自己的files_struct,那么创建子进程之后,就会将其files struct继承下来,这样的话两个进程也就指向了同一份内存空间,也就能通信了
在这里插入图片描述
至于这个内存空间是由谁提供的,或者是以什么方式提供的就决定了进程间通信的方式。目前我所了解的是三种方式:

1:管道

  • 匿名管道pipe
  • 命名管道

2:System V IPC

  • System V消息队列
  • System V共享内存
  • System V信号量

POSIX IPC

  • 消息队列
  • 共享内存
  • 信号量
  • 互斥量
  • 条件变量
  • 读写锁

进程数据交互:管道

什么是管道

管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”

在这里插入图片描述
如上,命令行who的标准输出原本是屏幕,但是却输出到了管道文件中,发生了重定向,然后wc命令再从以管道文件作为标准输入,然后输出到屏幕中。上述的who | wc -l就是应用匿名管道进行数据交互。

匿名管道

写端与读端

从who | wc -l可以看出,who作为一个进程是把内容写入管道文件,使用的是管道的写端,wc从管道中读入数据,使用的是管道的读端。
所以两个进程利用管道通信时,一个进程要使用管道的写端写入数据,另一个进程则要使用管道的读端读入数据,所以管道文件就要用两个文件描述符进行控制,一个控制读端,一个控制写端

父进程创建了管道

在这里插入图片描述

子进程同理

在这里插入图片描述

可以发现此时父子进程可以同时对管道进行写入的和读取,但是管道只能一端写入一端读入,所以要进行调整
在这里插入图片描述

建立匿名管道的函数

其函数原型为int pipe(int fd[2]),头文件是unistd.h,传入函数pipe后在其内部分别以读写的方式打开管道文件,默认情况下,fd[0]和fd[1]会分别获得文件描述符,其中fd[0]表示读端,fd[1]表示写端,返回值:成功返回0,失败返回-1。

其pipe内部函数的模拟实现可能是这样的:

在这里插入图片描述
有很多同学在这里会感到疑惑,因为用于进程间通信的管道文件就只有一个,为什么会有两个文件描述符呢?(默认是3和4)

其实这一点在之前的基础IO中我没有表示特别清楚,以读方式的打开一个文件,会分配一个描述符(假设是3),然后再以写方式打开刚才的你文件也会分配一个描述符(假设是4),这里的3和4操作的是一个文件,只不过一个负责读,一个负责写

最简单的进程间通信

为了观察方便,对父子进程都是用死循环。子进程每隔一秒读入一段信息this is the data that the child process wrote用来证明子进程写入了数据;对于父进程则取读取数据,一旦读完数据,就输出the father process got the information,用来证明父进程读取到了数据

注意pipe和fork创建后需要关闭一个读端和写端,如下所示。


#include <fcntl.h>                                                                                                     
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
   
  int pipefd[2] = {
   0};
  pipe(pipefd);
  //pipefi[0] write, else read 
  pid_t id = fork();
  if(id == 0)
  {
   
    //child
    close(pipefd[0]);
    const char* msg = "this is the data that child process wrote";
    while(1)
    {
   
      write(pipefd[1], msg, strlen(msg));
      sleep(1);
    }
  }
  else{
   
    //father
    close(pipefd[1]);
    char buffer[64] = {
   0};
    while(1)
    {
   
      ssize_t ret = read(pipefd[0], buffer, sizeof(buffer) - 1);
      //judge whether to read in 
      if(ret > 0)
      {
   
        buffer[ret] = '\0';
        printf("the father process got the information: %s\n",buffer);
      }
      sleep(0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值