匿名管道
进程间通信
计算机系统中有很多进程,这些进程之间可能会存在特定的需要协同工作的场景,而这种一个进程把自己的数据交付给另一个进程,让其进行处理这就叫做进程间通信。但是进程具有独立性,我们想要让进程之间进行交互,成本一定很高,因此操作系统需要对通信方式进行一定的设计。那么如何设计才能让两个进程之间互相通信呢?两个进程之间想要互相通信,首先需要让他们两个能够看到同一份公共资源,这里的资源就是一段内存,两个进程都能访问同一部分内存,这样两个进程都能够进行对这段内存的读写操作,就可以实现通信,因此进程通信的本质其实是由操作系统参与,提供一份所有通信进程能看到的公共资源。
进程间通信方式
现在常用的有如下几种通信方式:管道、System V进程间通信、POSIX进程间通信,其中他们各自又可以分为具体的几种方式
管道
管道可以分为匿名管道pipe和命名管道,这篇博客主要介绍管道的用法
System V IPC
- System V 消息队列
- System V 共享内存
- System V 信号量
POSIX IPC
- 消息队列
- 共享内存
- 信号量
- 互斥量
- 条件变量
- 读写锁
管道
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”,管道是一个只能单向通信的通信信道,大致结构如下:
创建管道
在代码中可以使用pipe命令创建一个管道,其中pipefd[2]是一个输出型参数,我们想通过这个参数读取到打开的两个fd。
执行如下代码,可以观察pipe所创建的两个文件描述符的具体内容,其中打印结果分别为3和4.
int pipefd[2]={
0};
if(pipe(pipefd) != 0)//等于0创建成功
{
perror("pipe error!\n");
return 1;
}
printf("pipefd[0]: %d \n",pipefd[0]);
printf("pipefd[1]: %d \n",pipefd[1]);
return 0;
匿名管道
进程中存在父进程中创建了子进程的情况,对于这种情况子进程和父进程之间进行通信,可以使用匿名管道,代码测试如下:这里是让子进程每隔1s写入,父进程实时进行读取操作。
int pipefd[2]={
0};
if(pipe(pipefd) != 0)//等于0创建成功
{
perror("pipe error!\n");
return 1;
}
//0:读取端
//1:写入端
//目的是想让父进程进行读取,子进程写入
if(fork()==0)
{
//子进程
close(pipefd[0]);
const char* msg="hello world\n";
while(1)
{
write(pipefd[1],msg,strlen(msg));
sleep(1);
}
exit(0);
}
close(pipefd[1]);
while(1)
{
char buffer[64]={
0};
ssize_t s = read(pipefd[0],buffer,sizeof(buffer)-1);
buffer[s]=0;
if(s == 0)
{
printf("child quit\n");
break;
}
else if(s > 0)
{
buffer[s]=0;
printf("child %s\n",buffer);//没有让父进程sleeip
}
else
{
printf("read error\n");
break;
}
}
close(pipefd[0]);
}
这里可以看到父进程可以读取到子进程写入的内容,并且读端会等待写端写入。那么如果将父进程每隔一段时间读取一次会出现什么情况呢?
这里我们代码让子进程不断进行写入,父进程每隔1秒进行一次读取
int pipefd[2]={
0};
if(pipe(pipefd) != 0)//等于0创建成功
{
perror("pipe error!