目录
1. 进程间通信
1.1. 进程间通信的目的
1.2. 如何实现进程间通信
2. 管道通信
2.1. 匿名管道
2.1.1 创建匿名管道
2.1.2 . 深入理解匿名管道
2.2. 命名管道
2.2.1. 创建命名管道
3. system V 标准进程间通信
3.1. 共享内存
3.1.1. 实现原理
3.1.2. 代码实现
3.2. 消息队列(了解)
3.2.1 实现原理
3.3. 信号量(了解)
3.3.1. 实现原理
1. 进程间通信
1.1. 进程间通信的目的
进程之间可能会存在特定的协同工作的场景,而协同就必须要进行进程间通信,协同工作可能有以下场景。
- 数据传输:一个进程需要将它的数据发送给另一个进程
- 资源共享:多个进程之间共享同样的资源。
- 通知事件:一个进程需要向另一个或一组进程发送消息,通知它发生了某种事件。
- 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另 一个进程的所有陷入和异常,并能够及时知道它的状态改变
1.2. 如何实现进程间通信
由于一个进程是不能访问到另一个进程的资源的,即进程之前是具有独立性的。
那么进程之间要通信,就不能使用属于进程的资源,而应该使用一份公共的资源。
所以进程间通信的本质是:由OS参与,提供一份所以进程都能访问的公共资源。
而公共资源是什么,例如:文件、队列、内存块。
2. 管道通信
2.1. 匿名管道
适用场景:父子进程间通信。
基本原理:通过打开同一个文件,父子进程对文件进行读写操作,父子进程在文件内核缓冲区中写入或读出数据,从而实现通信。
2.1.1 创建匿名管道
使用接口
pipe:创建一个管道,参数为输出型参数,打开两个文件描述符(fd),返回值为0表示打开失败。
具体代码:
代码语言:javascript复制#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int pipefd[2] = {0};
if(pipe(pipefd) != 0)
{
perror("pipe");
return 1;
}
// 父进程读取数据,子进程写入数据
// 规定:pipedfd[0]为读取端,pipefd[1]为写入端
if(fork() == 0)
{
//child
close(pipefd[0]);// 关闭读取端
const char* msg = "hello worldn";
while(1)
{
write(pipefd[1], msg, strlen(msg));
sleep(1);
}
exit(0);
}
// father
close(pipefd[1]);// 关闭写入端
while(1)
{
char buffer[64] = {0};
ssize_t s = read(pipefd[0], buffer, sizeof(buffer));// 如果read的返回值是0,表示子进程关闭了文件描述符
if(s == 0)
{
printf("child quitn");
break;
}
else if(s > 0)
{
buffer[s] = 0;// 子进程写入时没有添加'#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int pipefd[2] = {0};
if(pipe(pipefd) != 0)
{
perror("pipe");
return 1;
}
// 父进程读取数据,子进程写入数据
// 规定:pipedfd[0]为读取端,pipefd[1]为写入端
if(fork() == 0)
{
//child
close(pipefd[0]);// 关闭读取端
const char* msg = "hello worldn";
while(1)
{
write(pipefd[1], msg, strlen(msg));
sleep(1);
}
exit(0);
}
// father
close(pipefd[1]);// 关闭写入端
while(1)
{
char buffer[64] = {0};
ssize_t s = read(pipefd[0], buffer, sizeof(buffer));// 如果read的返回值是0,表示子进程关闭了文件描述符
if(s == 0)
{
printf("child quitn");
break;
}
else if(s > 0)
{
buffer[s] = 0;// 子进程写入时没有添加'