Linux应用程序开(day13) ──fork()与vfork()、exec函数族

内容:

  • fork()与vfork()

fork()与vfork()

1.fork()函数的执行次序是不确定的,是由操作系统进行调度的,而vfork()的执行次序是确定的,先执行子进程,再执行父进程。

2.fork()函数创建的子进程是拷贝父进程然后重新开辟地址空间的,而vfork是子进程和父进程共享地址空间。

下面我们进行实验说明:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void main(){
	pid_t pid;
	int i;
	int tmp = 188;
	pid = vfork();
	if(pid<0)
	{
		perror("error");
	}
	if(pid == 0)
	{
		for(i=0;i<3;i++)
		{
			printf("子进程,pid:%d,ppid%d \n",getpid(),getppid());
			tmp++;
			sleep(1);
		}
		_exit(0);
	}else
	{
		while(1)
		{
			printf("父进程,pid:%d,ppid%d \n",getpid(),getppid());
			printf("父进程,tmp:%d \n",tmp);
			sleep(1);
		}
	}
}

首先我们使用fork()函数创建子进程,然后在子进程中对变量tmp进行++,因为fork()是开辟了新的空间,子进程中的tmp的父进程的tmp是不同的两个,所以父进程中的tmp还是188.同时fork函数是子进程父进程随机执行,执行结果如下。
在这里插入图片描述
然后我们使用vfork()函数创建子进程,然后在子进程中对变量tmp进行++,因为vfork()是子进程父进程共用一块地址空间,所以子进程中的对tmp进行++,父进程中也会跟着就该,所以父进程中的tmp还是191.同时vfork函数是子进程先执行父进程后执行,执行结果如下。
在这里插入图片描述

exec函数族:

exec指的是一组函数,一共有六个函数,分别是:

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

其中execve()是真正的系统调用,其余5个都是C语言封装好的函数,主要是为了适应多种类型的参数列表,其他5个函数最终也是调用的execve()这个函数。

execl():

参数:文件路径,…(可变形参,一般以文件名开头 以NULL结尾)
这里要注意的是文件名称也是一个参数,以下都是。
代码:

#include <stdio.h>
#include <unistd.h>

void main(){
	
	execl("/home/glq/class/hello.out","hello.out",NULL);
}
execlp():

参数:文件名称,…(可变形参,一般以文件名开头 以NULL结尾)
代码:

#include <stdio.h>
#include <unistd.h>

void main(){

        execlp("ls","ls","-alh",NULL);
}
execle():

参数:文件路径,…(可变形参,一般以文件名开头 以NULL结尾),环境变量参数
代码:

#include <stdio.h>
#include <unistd.h>

void main(){

        execle("/home/glq/class/hello.out","hello.out",NULL,NULL);
}
execv():

参数:文件路径,数组 一般以NULL结尾
代码:

#include <stdio.h>
#include <unistd.h>

void main(){
        char *arg[]={"hello.out",NULL};

        execv("/home/glq/class/hello.out",arg);
}
execvp():

参数:文件名称,数组 一般以NULL结尾
代码:

#include <stdio.h>
#include <unistd.h>

void main(){
        char *arg[]={"ls","-alh",NULL};

        execvp("ls",arg);
}
execve():

参数:文件路径,数组 一般以NULL结尾,环境变量参数
代码:

#include <stdio.h>
#include <unistd.h>

void main(){
        char *arg[]={"hello.out",NULL};

        execve("/home/glq/class/hello.out",arg,NULL);
}

作业:

用vfork()函数创建子进程,在子进程里通过execv函数调用一个自定义程序。分别在子进程、父进程和自定义程序里打印进程号和父进程号。
详解:
大概流程就是先用vfork()创建一个子进程,然后判断是子进程还是主进程,如果是子进程就输出pid和ppid,然后用execl调用一下test.out这个程序,在这个程序中输出一下pid和ppid;如果是父进程就直接输出pid和ppid。这里要注意的是虽然是vfork创建的,但是父进程并不会等到test.out这个执行完毕以后才执行,所以为了不让test.out这个变成孤儿进程,我们把父进程中sleep(2),等待test.out执行完毕。具体的程序如下:
hello.c:

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

void main(){
        printf("tese程序----进程号:%d,父进程号:%d\n",getpid(),getppid());
}

mian.c:

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

void main(){


        pid_t pid;
        pid = vfork();
        if(pid < 0)
        {
                perror("fork error \n");
        }
        if(pid == 0)
        {
                printf("main程序 子进程----进程号:%d,父进程号:%d\n",getpid(),getppid());
                execl("/home/glq/hw/day18/test.out","test.out",NULL);

        }else
        {
              sleep(2);
                printf("main程序 主进程----进程号:%d,父进程号:%d\n",getpid(),getppid());

        }
}

运行结果如下:
在这里插入图片描述

谢谢大家的观看,如有错误请指正,谢谢! CSDN记录成长!
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值