vfork和fork的区别,Linxu下管道的使用(C语言)

7 篇文章 0 订阅
5 篇文章 0 订阅

目录

一、fork 和 vfork区别

二、vfork的创建

三、进程之间通信方式

1、 为什么要实现进程之间的通信

2、在linux下,进程之间通信方式和特点有哪些

四、进程间通信--无名管道

1、创建无名管道

2、程序测试

五、进程间通信--有名管道

1、创建有名管道

2、程序测试

六、总结


一、fork 和 vfork区别

fork()父子进程的执行次序不确定。
fork()子进程拷贝父进程的数据段和代码段,这里通过拷贝页表实现。
vfork()子进程与父进程共享地址空间,无需拷贝页表,效率更高。
vfork()保证子进程先运行,在调用 exec 或 exit 之前与父进程数据是共享的。父进程在子进程调用 exec 或 exit 之后才可能被调度运行,如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

二、vfork的创建

#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);

函数作用:

创建一个子进程,子进程共享父进程的地址空间(准确来说,在调用 exec(进程替换) 或 exit(退出进程) 之前与父进程数据是共享的)

特点:

1、子进程共享父进程的地址空间(准确来说,在调用 exec(进程替换) 或 exit(退出进程) 之前与父进程数据是共享的)

2、一定是子进程先运行,而且是等子进程结束之后,父进程才开始运行

3、当子进程调用exit之后,父进程才会往下执行

4、你在引用的时候,最好尽快结束子进程

5、用 vfork() 创建进程,子进程里一定要调用 exec(进程替换) 或 exit(退出进程),否则程序则会导致死锁,是有问题的程序,没有意义。

例子:

#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    int a = 100;
    
    //创建一个子进程
    pid_t id = vfork();
    if(id == -1)
    {
        printf("fork error\n");
        return -1;
    }

    else if(id >0)//父进程
    {
        printf("a1=%d\n",a);  
        //休眠
        wait(NULL);
        printf("a3=%d\n",a);
    }

    else if(id == 0)//子进程,vfork是先执行子进程先
    {
        a = 250; //父进程修改变量a的值
        printf("a2=%d\n",a);
        sleep(1);
        exit(0);//让子进程到这里就结束
    }

    return 0;
}

三、进程之间通信方式

1、 为什么要实现进程之间的通信

例如:

./project -> 开启了一个名字叫project的进程。

./test -> 开启了一个名字叫test的进程。

通过学习进程之间的通信,使得不同的进程之间能够实现数据的交换,例如test进程发送数据给project进程,project进程收到数据之后,根据数据做出相应的事情。 (test进程控制project进程)

2、在linux下,进程之间通信方式和特点有哪些

以下几种进程之间的通信有一个共通的特点,都是只能在同一台主机内部的进程使用。

1)管道通信。

管道通信分为有名管道(类型:p)与无名管道,管道是一个特殊的文件,进程通过将数据写入到管道中,另外一个进程从管道中读取数据出来。

2)信号

在linux下,有非常多的信号,例如:暂停,继续,停止...,某一个进程通过发送信号给另外一个进程,从而控制另外一个进程的运行状态。

3)消息队列

某一个进程把消息发送到队列上,另外一个进程就可以读取队列上的数据,消息队列好处:进程可以读取队列上某一个特定的数据。

4)共享内存

多个进程访问同一片内存空间。

四、进程间通信--无名管道

1、创建无名管道

无名管道只能作用于亲缘关系的进程之间的通信,例如父子进程。无名管道就是一个没有名字的管道文件,相当于一个队列结构,fd[1]为写入端(入队),fd[0]为读出端(出队)。其中信息读出后即删除,再次读取时即为下一个信息。

#include <unistd.h>
int pipe(int pipefd[2]);   -> 执行这个函数之后,得到两个文件描述符

函数作用:

创建一个无名管道文件

参数:

pipefd 一个具有2个int类型变量的数组。

返回值:

成功:0      失败:-1

2、程序测试

例子(实现两个进程间的通信):

#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

int main()
{
    int fd[2],fd1[2];
    //创建一个无名管道文件,pipefd[0] 读端  pipefd[1] 写端
    pipe(fd);
    pipe(fd1);

    //创建一个子进程
    pid_t id = fork();
    if(id == -1)
    {
        perror("failed");
        return -1;
    }

    //父进程
    else if(id > 0)
    {
        char buf[512]={0};
        char buf1[512]={0};
        close(fd[0]);  //关闭管道的读
        close(fd1[1]); //关闭另一个管道的写
        while(1)
        { 
            //等待输入
            printf("父亲说:");
            scanf("%s",buf);
            //写进管道
            write(fd[1],buf,sizeof(buf));
            //判断如果对于quit则退出
            if(strcmp(buf, "quit") == 0)
            {
                break;;
            }
            //清空
            bzero(buf,0);
            //读取管道
            read(fd1[0],buf1,sizeof(buf));  
            printf("父亲听到:%s\n",buf1); 
            //清空
            bzero(buf1,0);
        }
        //关闭无名管道
        close(fd[1]);
        close(fd1[0]);
        //进程休眠
        wait(NULL);
    }

    //子进程
    else if(id == 0)
    {
        close(fd[1]);  //关闭管道的写
        close(fd1[0]); //关闭别一个管道的读
        char buf[512]={0};
        char buf1[512]={0};
        sleep(1);
        while(1)
        {
            //清空
            bzero(buf,0);
            //读取管道
            read(fd[0],buf,sizeof(buf));  
            printf("儿子听到:%s\n",buf);
            //判断如果对于quit则退出 
            if(strcmp(buf, "quit") == 0)
            {
                break;;
            }
            //清空
            bzero(buf,0);
            //等待输入
            printf("儿子说:");
            scanf("%s",buf1);
            //写入管道
            write(fd1[1],buf1,sizeof(buf));      
            //清空
            bzero(buf1,0);

        }
        //关闭无名管道
        close(fd[0]);
        close(fd1[1]);
        //退出进程
        exit(0);
    }
    return 0;
} 

结果:

 

五、进程间通信--有名管道

1、创建有名管道

有名管道文件就是一个有名字的管道文件。在linux下,所有的进程都是可以看到这个文件,所以有名管道作用范围是整个linux系统下任意的两个进程。

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);

函数作用:

创建一个有名管道文件

参数:

pathname 有名管道文件的路径+名字。   例如: /home/gec/fifo_test

mode 管道文件的权限 0777

返回值:

成功:0        失败:-1

2、程序测试

例子(实现两个进程间的通信):

写入数据.c

#include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#define  FIFO_FILE  "/home/gec/fifo1"

int main(void)
{
    //先判断文件是否存在,如果存在则不用创建了
    if(access(FIFO_FILE, F_OK) == -1)//access 判断文件是否存在,如果不存在则返回 -1
    {
        //创建一个有名管道文件  
        if(mkfifo(FIFO_FILE,0777) == -1)
        {
            perror("mkfifo error");
            return -1;
        }   
    }
    //发送数据 ,往有名管道文件中写入数据
    
    //1、打开有名管道文件
    int fd = open(FIFO_FILE,O_RDWR);
    if(fd == -1)
    {
        perror("open fifo error");
        return -1;
    }

    //2、写入数据 
    while(1)
    {
        printf("请输入数据:");
        char sendbuf[1024]={0};
        scanf("%s",sendbuf);        
        write(fd,sendbuf,strlen(sendbuf));

        if(strcmp(sendbuf,"exit") == 0)
            break;      
    }

    //3、关闭文件
    close(fd);
    return 0;
}

读取数据.c

#include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#define  FIFO_FILE  "/home/gec/fifo1"

int main()
{
    //先判断文件是否存在,如果存在则不用创建了
    if(access(FIFO_FILE, F_OK) == -1)//access 判断文件是否存在,如果不存在则返回 -1
    {
        //创建一个有名管道文件  
        if(mkfifo(FIFO_FILE,0777) == -1)
        {
            perror("mkfifo error");
            return -1;
        }   
    }
    
    //从管道文件中读取数据,并且打印出来    
    //1、打开有名管道文件
    int fd = open(FIFO_FILE,O_RDWR);
    if(fd == -1)
    {
        perror("open fifo error");
        return -1;
    }
    //2、从管道文件中读取数据 
    while(1)
    {
        char recvbuf[1024]={0};
        read(fd,recvbuf,sizeof(recvbuf));
        
        printf("recvbuf:%s\n",recvbuf);     
        if(strcmp(recvbuf,"exit") == 0)
            break;          
    }

    //3、关闭文件
    close(fd);
   

六、总结

1.管道是创建在内存中,进程结束空间释放,管道不复存在。

2.无名管道和有名管道都是半双工通信,实现双向通信需要建立两个管道。

3.无名管道是linux特殊文件。

4.无名管道只用于父子进程之间,有名管道可用于任意两个进程之间。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值