Linux 进程间通信

进程间通信

  • 数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。
  • 共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件。
  • 资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

信号

通过注册信号与全局变量的结合达到进程间通信
优点:实时,不阻塞
缺点:不安全,内容固定
案例:

void func(int n)
{
    printf("ping\n");
     // how to send signal 4 to the second process?
}
void func2(int n)
{
  printf("pong\n");
  // how to send signal 3 to the first process?
}
int main()
{
  pid_t pid;
  int i;
  for(i = 0; i < 2; i++){
    pid = fork();
    if(pid == 0){
      if(i == 0){
        signal(3, func);
      }else{
        signal(4, func2);
      }
      while(1);
    }else{
      if(i == 1){
        sleep(3);
        // how to send signal 3 to the first child process?
        sleep(3);
        // how to kill the two children?
      }
    }
  }
  return 0;
}

管道

  • 管道是针对于本地计算机的两个进程之间的通信而设计的通信方法,管道建立后,实际获得两个文件描述符:一个用于读取而另外一个用于写入。
  • 最常见的IPC机制,通过pipe系统调用。
  • 管道是单工的,数据只能向一个方向流动,需要双向通信时,需要建立起两个管道。
  • 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
  • 通过打开两个管道来创建一个双向的管道
  • 管道是阻塞性的,当进程从管道中读取数据,若没有数据进程会阻塞。
  • 当一个进程往管道中不断地写入数据但是没有进程去读取数据,此时只要管道没有满是可以的,但若管道放满数据的则会报错。

匿名管道

  • 在关系进程中进行(父进程和子进程、兄弟进程之间)
  • 由pipe系统调用,管道由父进程建立。
  • 管道位于内核空间,其实是一块缓存。
  • int pipe(int fd[2]);
    • 功能:创建匿名管道pipe
    • 返回: 成功返回0 ,出错返回-1
    • fd[0]: 为pipe的读端,用于读取管道;fd[1]: 为pipe的写端,用于写入管道

案例:

int main()
{
  //匿名管道,第一步:定义一个整型的长度为2的数组
  int fd[2] = { };
  if(pipe(fd)){
    perror("管道创建失败\n");
    exit(-1);
  }
  int pid = fork();
  if(pid == 0){//子进程 -- 读消息
    close(fd[1]);
    while(1){
      printf("子进程正在等待消息...\n");
      char buffer[1024] = " ";
      read(fd[0],buffer,1024) ;
      printf("读取到%s\n",buffer);
      if(strcmp(buffer,"end") == 0) break;
    }
    close(fd[0]);
  }else if(pid > 0){//父进程 -- 写消息
    close(fd[0]);
    while(1){
      char buffer[1024] = " ";
      printf("请输入你要发送的内容\n");
      scanf("%s",buffer);
      write(fd[1],buffer,strlen(buffer));
      if(strcmp(buffer,"end") == 0) break;
    }
    wait(NULL);
  }else{
    perror("进程创建失败\n");
    exit(-1);
  }
  return 0;
}

命名管道

  • 两个没有任何关系的进程之间通信可通过命名管道进行数据传输,本质是内核中的一块缓存,另在文件系统中以一个特殊的设备文件(管道文件)存在。
  • 只要对FIFO有适当访问权限,FIFO可用在任何两个没有任何关系的进程之间通信。
  • 本质是内核中的一块缓存,另在文件系统中以一个特殊的设备文件(管道文件)存在。
  • 在文件系统中只有一个索引块存放文件的路径,没有数据块,所有数据存放在内核中。
  • 命名管道必须读和写同时打开,否则单独读或者单独写会引发阻塞。
  • 对FIFO的操作与操作普通文件一样,一般的文件I/O函数都可用于FIFO。
  • 通过系统调用mkfifo创建
  • int mkfifo(const char * pathname, mode_t mode);
    • 功能:创建命名管道
    • 返回:若成功则返回0 ,出错返回-1

案例:

int main()
{
  if(access("pipe",F_OK)){
    if(mkfifo("pipe",0664)){
      perror("创建管道文件失败\n");
      exit(-1);
    }
  }
  int fd = open("pipe",O_RDWR);
  if(fd < 0){
    perror("打开文件失败\n");
    exit(-1);
  }
  while(1){
    char buffer[1024] = " ";
    printf("请输入内容\n");
    fgets(buffer,1024,stdin);
    write(fd,buffer,strlen(buffer));
    if(strcmp(buffer,"end") == 0) break;
  }
  close(fd);
  return 0;
}
int main()
{
  if(access("pipe",F_OK)){
    if(mkfifo("pipe",0664)){
      perror("创建管道文件失败\n");
      exit(-1);
    }
  }
  int fd = open("pipe",O_RDWR);
  if(fd < 0){
    perror("打开文件失败\n");
    exit(-1);
  }
  while(1){
    char buffer[1024] = " ";
    read(fd,buffer,1024);
    printf("%s\n",buffer);
    if(strcmp(buffer,"end") == 0) break;
  }
  close(fd);
  return 0;
}

popen管道

  • The popen() function opens a process by creating a pipe, forking, and invoking the shell.
  • FILE *popen(const char *cmdstring, const char *type);
    • 返回值: 成功返回文件指针,出错返回NULL
  • int pclose(FILE *fp);
    • 返回值: cmdstring 的终止状态,出错返回-1

案例:

int main()
{
  // FILE *popen(const char *command, const char *type);
  // command:执行的shell命令
  // type:打开方式。只能是 "r",或者"w"其他都会报错
  // 本质上:创建一个管道,执行command命令,并将执行的结果保存到管道里面。 
  FILE* fp = popen("ls","r");
  if(fp == NULL){
    perror("创建管道失败\n");
    exit(-1);
  }
  while(1){
    char buffer[1024] = " ";
    if(fgets(buffer,1024,fp) == NULL)   break;
    printf("%s",buffer);
  }
  printf("\n");
  pclose(fp);
  return 0;
}

消息队列

共享内存

信号量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值