我们经常可以看到, 诸如Chrome/VSCode之类的程序打开运行的时候, 可以在后台看到会有多个相关进程启动. 同一个程序启动的不同进程间, 必然存在合作关系, 那么这些进程之间是如何合作的呢?
IPC
进程间通信也叫做IPC(InterPorcess Communication). 进程间通信可以让不同的进程共同合作完成某些任务.
不同进程的虚拟内存空间可能会映射到不同的物理内存空间, 但是虚拟内存空间中的虚拟内核空间都会映射到相同的物理内核空间, 因为一般认为系统的内核只有一个.
不同进程映射到相同物理内核空间
所以, 为了剔除用户空间映射不一致的影响, 可以在内核空间操作, 只要在内核空间中开辟相同的物理内存, 供不同进程访问, 那么就可以做到IPC.
内核提供共享区域做IPC
或者, 可以使用文件做IPC. 不同进程只要能够指向相同的文件, 再加上对文件的访问控制, 就可以在不同进程间通过文件系统通信.
使用文件系统做IPC
再或者, 可以通过我们熟知的网络链接做IPC.
通过网络做IPC
匿名管道
C提供了pipe函数用于创建管道. pipe是内核在内核空间提供的一段缓存区.
pipe
|
|
pipe输入参数是包含两个pipe描述符的二元数组. pipe执行失败返回-1, 执行成功则返回0, 同时第一个pipe描述符PIPEDES[0]指向pipe的读端, 第二个pipe描述符PIPEDES[1]指向pipe的写端. 调用pipe之后我们拿到了读写端口, 然后再调用fork函数, 现在父子进程都拿到了pipe的读写端口.
父子进程都拿到了pipe的读写端口
Create a one-way communication channel (pipe).
函数注释中已经说明, pipe是一个one-way communication channel, 只能一个通路, 也就是说只能从一端进一端出, 所以在父子进程必须确定谁来发送, 谁来接收, 不用的端口需要关闭.
下面的例子使用子进程写, 父进程读:
|
|
int main()
{
int pipef[2] = {0, 0};
int ret = pipe(pipef);
if (ret < 0)
{
printf("create pipe error\n");
return -1;
}
printf("pipef[0] %d, pipef[1] %d\n", pipef[0], pipef[1]);
int pid = fork();
if (pid < 0)
{
printf("fork error\n");
return -1;
}
else if (pid == 0)
{
//close read
close(pipef[0]);
char msg[128] = "pipe message.";
int count = 5;
while(count-- > 0)
{
strcat(msg, "+");
int write_stat = write(pipef[1], msg, sizeof(msg));
printf("child send[%d]: %s\n", write_stat, msg);
// sleep(1);
}
printf("write complete\n");
close(pipef[1]);
}
else
{
//close write
close(pipef[1]);
char msg[1024] = {0};
int count = 5;
while(count-- > 0)
{
int read_stat = read(pipef[0], msg, sizeof(msg));
if