管道,管道分为命名管道和无名管道,他们的区别主要是初始化的方式不同。
- ①管道的存取:命名管道是一个实际存在于文件系统的特殊类型文件对应了内存索引节点,这中间会维护一个读偏移量和写偏移量。当一个进程以读的方式打开管道后(系统调用read),如果此时还没有任何其他进程试图往该管道里面写数据,那么内核会让这个读进程进入睡眠状态,直到另一个进程以写的方式打开该管道,并往里面写入数据(写的方式和写普通文件完全一样,先写到内核的高速缓冲区中,然后再延迟写到对应的磁盘上。在内核中会维护一个固定大小的环形队列来处理写入的磁盘块缓冲,即管道其实是有大小限制的。当试图写入的字节数小于容量时,内容被写入到环形队列中,同时向后移动写偏移量,便于下一次写入。当写入的进程操作完毕后(关闭了对应的fd),内核会唤醒因等待读管道而被睡眠的进程,如果有多个进程在等待读取,则都会被唤醒,采用竞争的方式,最终有一个进程会读到管道内的内容,而其他读进程再次被内核睡眠。
- ②管道的清除:当完成了一次写入和读取后,如果此时没有正在睡眠的等待写入的进程的话,内核就会默认管道已不被需要,而唤醒所有等待读的进程,返回读到了0个字节,并清除管道对应的内存索引节点中的信息,将管道大小初始化。即在操作管道的时候,必须确保连续的写入和读取,如果中间有断层,那么这个管道很有可能被系统回收。比较典型的例子是python的多线程,会根据时间片进行任务的切换,如果时间片到的时候,正在写入,此时被切换到其他线程的话,很有可能再切换回来的时候,已经无法再往管道中写入数据了,管道可能已经被内核回收了。