在这一篇文章当中,已经简单提到什么是进程
目录
进程之间的通信方式有哪些:
方式一:管道
匿名管道(3个特点)
特点1:没有名字标识,通信的数据是无格式的流并且大小受到限制。
特点2:方向单一,只能在一个方向上面流动。(只能用于父子关系进程之间的通信)
特点3:生命周期随着进程的创建而产生,随着进程的结束而消亡。
命名管道(2个特点)
特点1:支持非亲缘关系进程之间的通信。
特点2:需要在文件系统创建一个类型为 p 的设备文件,那么毫无关系的进程就可以通过这个设备文件进行通信。
另外,不管是匿名管道还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据时候自然也是从内核中获取
方式二:消息队列
消息队列是一个保存在内核的消息链表。
链表的数据类型是用户自定义的(但是需要发送方和接收方之间进行约定)
每次数据的写入和读取都需要经过用户态与内核态之间的拷贝过程。
方式三:共享内存
指的是多个进程共享一块内存,这一块内存用于各个进程之间进行通信。
共享内存的优点:
操作系统为各个进程分配一组共享的内存,每一个进程都可以直接进行访问,就好像进程单独访问自己的空间一样快捷。
不需要陷入内核态或者系统调用。
共享内存的缺点:
多个进程竞争共同的共享资源的时候会造成数据的错乱。
方式四:信号量
信号量其实就是一个计数器:显示的是可以申请资源的数量
支持两个操作,一个是P操作,另外一个是V操作,这两个操作都是原子性的
首先申请一块共享的资源,同一时间只有一个进程可以访问共享的资源。
每申请一次,信号量就-1,归还一次,信号量就+1。如果信号量为0了还申请,就会被阻塞。
方式五:信号
只有在进程出现了异常的时候,才会使用信号进行通信。(例如kill相当于发送SIGKILL信号来终止进程)
信号是进程间通信机制中唯一的异步通信机制,因为可以在任何时候发送信号给某一进程,一旦有信号产生,我们就有下面这几种,用户进程对信号的处理方式。
1.执行默认操作。
2.捕捉信号。
3.忽略信号
方式六:Socket
Socket其实主要就是用于不同的主机/服务器之间的通信了。
例如在socket编程当中,服务端TCP需要调用socket.accept()方法来接收客户端的请求。返回一个socket对象。
IO多路复用
最基础的 TCP 的 Socket 编程,它是阻塞 I/O 模型,基本上只能一对一通信,那为了服务更多的客户端,我们需要改进网络 I/O 模型。
IO多路复用,就是使用一个进程来维护多个Socket。
IO多路复用有3种实现的方式:select、poll、epoll。
select&poll
一个进程使用线性结构来处理socket集合
select 和 poll 并没有本质区别,它们内部都是使用「线性结构」来存储进程关注的 Socket 集合。在使用的时候,首先需要把关注的 Socket 集合通过 select/poll 系统调用从用户态拷贝到内核态,然后由内核检测事件。
epoll
Socket 集合越大,Socket 集合的如果遍历和拷贝会带来很大的开销,因此也很难应对 C10K。
epoll如何解决?
方案1:使用「红黑树」来关注进程所有待检测的 Socket。也就是变线性结构为树形结构
方案2:内核里维护了一个「链表」来记录就绪事件,只将有事件发生的 Socket 集合传递给应用程序,不需要像 select/poll 那样轮询扫描整个集合(包含有和无事件的 Socket ),大大提高了检测的效率。