操作系统 --- 进程通信 IPC Inter Process Communication

为什么需要进程通信

  • 不同的进程之间需要交换大量的数据

进程通信的方法

pipeline

什么是pipeline

  • pipe是一块内存,被视为"virual file" (实际不是file 不在文件系统中, 而是存在于内存之中的一块缓冲区)
  • pipe是单向通信,pipe的一端连接输出进程(read end),一端连接输入进程(write end),
  • read end和write end是两个file descriptor(数据类型是int)
  • 一般会创建一个int数组: fd[2], fd[0]代表read end, fd[1]代表write end
  • 主要用于父进程和子进程之间,或者有共同祖先的两个进程, 因为需要父进程创建pipe
  • 进程结束后,pipe被自动释放

shell中的pipe

  • 在shell中 “ | ” 代表pipeline
  • 可以将 “|" 前面的commond处理完的数据传给后面的command
    在这里插入图片描述

创建过程

  • 一个进程创建完pipe之后,write end和read end都在同一进程里
  • 然后这个进程fork一个子进程,此时子进程也同时拥有write end和read end
  • 父进程关掉其中一端,子进程关掉另外一端,实现单向通信
    在这里插入图片描述

pipe的同步机制

  • 管道自带同步互斥机制:
    管道的内核实现:fs/pipe.c ,主要通过内核的锁以及等待队列等机制实现
  • 管道的write操作会阻塞进程
    当内存缓冲区已满或被读进程锁定,会阻塞write操作
    当所有数据被写入管道时write操作才会结束
  • 管道的read操作会阻塞进程
    当读进程被阻塞时会形成等待队列,并让等待队列进入休眠
    当所有子进程关闭管道的写入端的操作时会停止阻塞
    父进程的写入端操作关闭时,父进程的读操作会停止阻塞
  • 当所有读取端和写入端都关闭后,管道才能被销毁
    ————————————————
    版权声明:本文为优快云博主「z_stand」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.youkuaiyun.com/Z_Stand/article/details/100806493

实现pipe通信 — system call: pipe()

父进程和子进程之间

  • 创建一个进程A,然后创建pipe
  • 进程A fork一个进程B
  • 进程A关闭write end
  • 进程B关闭read end

实现两个子进程之间的pipe通信

  • 创建一个进程A,并创建pipe
  • 进程A fork一个子进程B, 子进程B关闭write end
  • 进程A 关闭read end,然后fork子进程C,此时子进程C只有read
  • 进程A关闭write end,和pipe脱离关系
  • 子进程B, C实现了单向通信
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
    int fds[2];
    char buff[60];
    int count;
    int i;
    pipe(fds);
    
    int pid1 = fork();
    if (pid1 == 0) {
	printf("Child process A %d: Read from the pipe \n", getpid());
	//child A close write, and has the read
        close(fds[1]);
	while ((count=read(fds[0], buff, 60)) > 0) {
	    for(i=0; i<count; i++) {
	        write(1, buff+i, 1);
		write(1, " ", 1);
	    }
	    printf("\n");
	}
	close(fds[0]);
	exit(0);
    }
    else {
        //parent close read
    	close(fds[0]);
	int pid2 = fork();
	if (pid2 == 0) {
	    //child B has the write since read is already closed by its parent
	    printf("Child process B %d: write to the pipe \n", getpid());
	    for(i=1; i<argc; i++) {
	        write(fds[1], argv[i], strlen(argv[i]));
	    }
	    exit(0);
	    
	}
	else {  
	    //parent close write
	    close(fds[1]);
	    wait(NULL);
        printf("This is the parent process %d\n", getpid());
	}
    }
    exit(0);
}

pipe的缺点

  • 没有名称,只能支持有共同祖先的进程之间的通信, 不能支持任意两个进程的通信
  • 进程结束之后pipe也被释放

FIFO (Named Pipe)

什么是FIFO or Named Pipe

  • 为了解决pipe的缺点,出现了named pipe
  • named pipe一般是一个真正的文件,存在于文件系统中,只要操作系统不关闭就一直存在
  • FIFO file就是named pipe的实现
  • 所有进程可以对FIFO file进行读写操作,就像读写正常文件一样
  • FIFO是多向通信

创建一个FIFO file — system call: mkfifo()

  • int mkfifo(const char *filename,mode_t mode);
    在这里插入图片描述

FIFO的同步机制

  • FIFO总是处于阻塞状态。
  • 当FIFO打开时设置了读权限,则读进程将一直“阻塞”,一直到其他进程打开该FIFO并且向管道中写入数据。这个阻塞动作反过来也是成立的,
  • 如果一个进程打开一个管道写入数据,当没有进程从管道中读取数据的时候,写管道的操作也是阻塞的,直到已经写入的数据被读出后,才能进行写入操作。
  • 如果不希望在进行命名管道操作的时候发生阻塞,可以在open()调用中使用 O_NONBLOCK标志,以关闭默认的阻塞动作。
    ————————————————
    版权声明:本文为优快云博主「Change_Improve」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.youkuaiyun.com/Change_Improve/article/details/98731329

shared memory

什么是shared memory

  • 多个进程可以访问同一块内存(正常情况下,进程不能互相访问对方的内存空间)

shared memory原理

  • 在Linux中,每个进程都有属于自己的进程控制块(PCB)和地址空间(Addr Space),并且都有一个与之对应的页表,负责将进程的虚拟地址与物理地址进行映射,通过内存管理单元(MMU)进行管理。两个不同的虚拟地址通过页表映射到物理空间的同一区域,它们所指向的这块区域即共享内存。
    ————————————————
    原文链接:https://blog.youkuaiyun.com/ypt523/article/details/79958188
    在这里插入图片描述

shared memory的问题

  • 下图中的读写操作不是原子操作(转换成汇编语言之后不是原子操作), 有可能在写入时读取或者读取时写入
  • 需要使用信号量(semaphore) 来实现同步与互斥
    在这里插入图片描述

使用shared memory

  • The ftok function creates a identifier to be used with the IPC functions (semget, shmget, msgget)
  • ftok token is valid across the system, so that two or more independent processes have the same access to IPC recourses (shared memory, message queue)
    在这里插入图片描述

message queue

  • message queue是存在内核中的一个链表
  • 通过message queue indentifier辨别
  • 通过system call操作
  • 比shared memory要慢

在这里插入图片描述

socket

To be continued

Windows和Linux采用的进程通信的方法

Windows

  • memory mapping
  • pipelines
  • messages

Linux

  • pipe (pipe),
  • FIFO (named pipe),
  • socket (socket),
  • SHM (Shared memory),
  • MSG queue (Message queue),
  • mmap (file map).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值