管道
分类:命名管道和匿名管道
- 命名管道:可以用于本机上的任意进程间通信
- 匿名管道:只适用于拥有亲缘关系的进程间通信
本质:是内核中开辟的一块缓冲区
特性:
- 读写特性:当一个进程读或者写时,其他进程不能读或者写
- 自带同步与互斥
- 半双工通信:数据只能向一段发送数据,若要双方通信,则要使用两个管道
- 提供字节流服务
- 生命周期随进程
匿名管道
原型
int pipe(int fd[2]);
fd:文件描述符数组,其中fd[0]表示读端,fd[1]表示写端
成功返回0,失败返回错误代码
//从键盘读取数据,写入管道,读取管道,写到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main( void )
{
int fds[2];
char buf[100];
int len;
if ( pipe(fds) == -1 )
perror("make pipe"),exit(1);
// read from stdin
while ( fgets(buf, 100, stdin) ) {
len = strlen(buf);
// write into pipe
if ( write(fds[1], buf, len) != len ) {
perror("write to pipe");
break;
}
memset(buf, 0x00, sizeof(buf));
// read from pipe
if ( (len=read(fds[0], buf, 100)) == -1 ) {
perror("read from pipe");
break;
}
// write to stdout
if ( write(1, buf, len) != len ) {
perror("write to stdout");
break;
}
}
}
用fork来共享管道原理
站在文件描述符角度深度理解管道
站在文件描述符角度看待这个问题之前,我们要理解一件事情,文件描述符的分配规则是最小未使用,0是标准输入,对应键盘,1是标准输出,对应显示器,2是标准错误,对应显示器,所以假设这里的进程未使用其他文件操作符,所以按照操作系统的分配规则,会给fd[0]分配3,fd[1]分配4
站在内核角度,看待管道本质
所以说,内核看待管道也是如同文件一样,管道的使用同文件一致,这也就符合Linux下一切皆文件的思想
管道的读写特性
当没有数据可读时
- O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
- O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
当管道满的时候
- O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
- O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
如果所有管道写端对应的文件描述符被关闭,则read返回0
如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程
退出
当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。
匿名管道特点
只能用于具有共同祖先的进程(据有亲缘关系的进程)之间进行通信,通常,一个管道由一个进程创建,然后由这个管道fork一个子进程,此后父子进程就可以应用该管道
管道提供流式服务
一般而言,进程退出,管道销毁,生命周期随进程
一般而言,内核会对管道操作同步和互斥
管道是半双工的,一般只能有一个进程向另一个进程发送消息,如果要两个进程互发消息,则需要创建两个管道
命名管道
匿名管道应用的一个限制就是只能在具有亲缘间关系的进程间通信,如果我们想要在不同进程间进行通信,就需要借助FIFO文件,它也被叫做命名管道,可以在命令行创建,也可以在程序内部创建,在命令行用mkfifo name创建,在程序内部借助函数
int mkfifo(const char* name ,mode_t mode);创建
匿名管道和命名管道的区别
- 匿名管道由pipe函数创建并打开
- 命名管道由mkfifo创建,用open打开
- FIFO(命名管道)和pipe(匿名管道)除了创建和打开的操作不同之外,之后的语义操作完全相同
共享内存
共享内存是IPC中最快的形式,这是因为共享内存是内存上的一块空间,少了两次用户态和内核之间的数据拷贝,所以是最快的
本质:在内存空间开辟一片空间,然后将这块地址映射到各个进程的进程空间中
消息队列
消息队列提供了一个从一个进程向另一个进程发送一块数据的方法
每个数据块都被认为是有一个类型,接收者进程接收的数据块可以由不同的类型值
信号量
信号量主要用于同步与互斥
由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种
关系为进程的互斥
系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。
在进程中涉及到互斥资源的程序段叫临界区
注意
IPC是系统资源,所以我们在使用他们之后,一定要记得删除掉,否则不会自动清除,除非重启,所以system V IPC资源的生命周期随内核
那么system V IPC有哪些呢?
消息队列,共享内存,信号量