进程间通信

Posted yangguang-it

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程间通信相关的知识,希望对你有一定的参考价值。

1.管道

技术图片

 

对于具有公共祖先的进程,其管道是建立在3-4G的内核空间中的。每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。

技术图片

技术图片

 

调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。

#include <sys/wait.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>                                                           
#include<stdlib.h>
#include<string.h>
int main(void)
{
    pid_t pid; 
    int fd[2];
    if(pipe(fd)<0)
    {
        perror("pipe");
        exit(1);
    }
    printf("fd[0]=%d, fd[1]= %d\\n",fd[0],fd[1]);
    if((pid=fork())<0)
        {
            perror("fork");
            exit(1);
        }
    else if(pid==0)//child
    {
        char c_str[1024];
        int n;
        close(fd[1]);//关闭写端口
        n=read(fd[0],c_str,sizeof(c_str)/sizeof(c_str[0]));//由于不知道读多少,所以读取最大长度
        close(fd[0]);
        write(STDOUT_FILENO,c_str,n);
    }
    else//parents
    {
        char str[]="hello pipe!\\n";
        sleep(2);
        close(fd[0]);//关闭读端口
        write(fd[1],str,strlen(str));
        close(fd[1]);
        wait(NULL);//等待回收子进程资源
    }
    return 0;
}

技术图片

 

在父进程没有传输数据在管道中时,子进程中的read函数会阻塞等待。我们可以使用fcntl函数改变一个已经打开文件的属性,如重新设置读、写、追加、非阻塞等标志。

#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>                                                           
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<errno.h>
int main(void)
{
    pid_t pid; 
    int fd[2];
    if(pipe(fd)<0)
    {
        perror("pipe");
        exit(1);
    }
    printf("fd[0]=%d, fd[1]= %d\\n",fd[0],fd[1]);
    if((pid=fork())<0)
        {
            perror("fork");
            exit(1);
        }
    else if(pid==0)//child
    {
        char c_str[1024];
        int n,flags;
        flags=fcntl(fd[0],F_GETFL);
        flags |=O_NONBLOCK;
        if(fcntl(fd[0],F_SETFL,flags)==-1)
        {
            perror("fcntl");
            exit(1);
        }
        close(fd[1]);//关闭写端口
tryagain:
        n=read(fd[0],c_str,sizeof(c_str)/sizeof(c_str[0]));//由于不知道读多少,所以读取最大长度
        if(n<0)
        {
            if(errno==EAGAIN)
            {
                write(STDOUT_FILENO,"try again...\\n",13);
                sleep(1);
                goto tryagain;
            }
            perror("read");
            exit(1);
        }
        close(fd[0]);
        write(STDOUT_FILENO,c_str,n);
    }
    else//parents
    {
        char str[]="hello pipe!\\n";
        sleep(2);
        close(fd[0]);//关闭读端口
        write(fd[1],str,strlen(str));
        close(fd[1]);
        wait(NULL);//等待回收子进程资源
    }
    return 0;
}

技术图片

此时,read已经不再是阻塞了。需要注意的是,使用管道技术,应该在fork之前创建管道。

 

2.FIFO

 

以上是关于进程间通信的主要内容,如果未能解决你的问题,请参考以下文章

进程间通信——管道

进程间通信

进程间通信

进程间通信

iOS进程间通信之CFMessagePort

操作系统实验3共享内存进程间通信实验