引言:
我们都知道,进程运行时是具有独立性的,要让两个进程进行通信是一件很困难的事情。因此两个进程通信的前提条件是,需要让两个进程看到同一份资源(物理内存)。
进程通信分类
管道:
- 1.匿名管道pipe(有“亲情”关系(多用于父子进程)的进程进行通信)
- 2.命名管道(实现不相关进程之间的通信)
System V IPC
- System V 消息队列
- System V 共享内存
- System V 信号量
POSIX IPC
- 消息队列
- 共享内存
- 信号量
- 互斥量
- 条件变量
- 读写锁
管道
- pipe函数:
头文件: #include<unistd.h>
原型:int pipe(int fd[2])
参数:文件描述符数组,其中fd[0]表示读端,fd[1]表示写端
成功,返回0。错误返回错误码
- 工作原理
- 父进程读写端一起打开文件(管道)
- 用fork创建子进程(子进程拷贝父进程代码,一样由读写段打开文件)
- 父子进程依照需求,分别关闭读端/写端。
- 让我们看看代码是如何实现匿名管道的:
int main()
{
int fd[2] = {
0};
pipe(fd);
pid_t id = fork();
if(id == 0)//子进程写
{
close(fd[0]);//关闭读操作符
char buf[] = "I'm child";
while(1)
{
write(fd[1], buf, strlen(buf));
sleep(1);
}
}
else//父进程读
{
close(fd[1]);//关闭写操作符
char ret[1024];
while(1)
{
ssize_t s = read(fd[0], ret, sizeof(ret) - 1);
if(s < 0)
{
printf("printf error");
break;
}
else if(s > 0)
{
ret[s] = 0;
printf("parent get child : %s\n", ret);
}
else
{
printf("parent get child : %s\n", ret);
break;
}
}
}
return 0;
}
结果:我们可以看到父进程读到了子进程中的信息。
管道读写的规则
关于临界关系的一些概念:
- 1.临界资源:多进程共享的内存资源(管道)
- 2.临界区:访问临界资源的代码
- 3.互斥:任何一个时刻只能由一个人访问临界区
- 4.饥饿问题:一个排在R队列中的进程很久都无法获得资源
- 5.同步:在保证临界资源安全的前提条件下(通常为互斥),让多进程访问临界资源具有一定的顺序性。功能:协同进程步调,避免饥饿问题
- 6.原子性:对于临界资源,要么访问完毕,要么不访问。
管道读写会发生的四种情况:
- 1.读端不读,读端关闭(写端到/0处,出异常)
- 2.写端不写,写端关闭(写端到/0处,出异常)
- 3.写端一直写,读端一直不读(阻塞)
- 4.读端一直读,写端一直不写(阻塞)
让我们看看这四种情况:
- 1.子进程一直在写,父进程不读
#include<unistd.h>
#include<stdio.h>