本文介绍: 答案是:可以使用 exit( )/_exit( )来退出并传递退出值,使用 wait( )/waitpid( )来使父进程阻塞 (sè) 等待进程,顺便还可以帮子进程收尸。父进程如果需要可以使用 wait( )/waitpid( )来获得子进程正常退出退出值, 当然,这两个函数可以使得父进程阻塞等待子进程的退出。所谓的“退出处理函数”指的是进程使用 exit( )退出时被自 动执行函数需要使用 atexit( )来注册。所谓的退出状态不是退出值,退出状态包括了退出值。3.1 execl函数

1. fork函数

这个函数接口本身非常简单简单到连参数没有,但是这个函数有个非常与众不同的 地方:他会使得进程一分为二!就像细胞分裂一样:

父子进程是相互独立的:由于子进程完整地复制了父进程的内存空间,因此从内存 空间的角度看他们是相互独立互不影响

fork.c

#include<unistd.h&gt;
#include<stdio.h>
#include <stdlib.h>

//使用fork函数
int b = 40;//数据段的全局变量

int main()
{

    int a = 10;//栈空间申请局部变量
    int* p = (int*)malloc(sizeof(int));//堆空间
    *p = 80;

    pid_t pid = fork();//创建一个子进程,此行代码后面所有的代码,子进程都会原封不动的复制一份执行

    if(pid==0){//子进程
        a = 20;
        b = 50;
        *p = 100;
        printf("子进程:%dn",a);//20
        printf("子进程:%dn",b);//50
        printf("子进程:%dn",*p);//100
    }
    if(pid>0){
        sleep(1);
        printf("父进程:%dn",a);//10
        printf("父进程:%dn",b);//40
        printf("父进程:%dn",*p);//80
    }

    return 0;
}

2 _exit、exit和wait、waitpid

2.1 _exit、exit、atexit

那么怎么让子进程先运行并退出之后,父进程再继续呢?子进程的退出状态 又怎么传递给父进程呢?答案是:可以使用 exit( )/_exit( )来退出并传递退出值,使用 wait( )/waitpid( )来使父进程阻塞 (sè) 等待子进程,顺便还可以帮子进程收尸

所谓的“退出处理函数”指的是进程使用 exit( )退出时被自 动执行函数需要使用 atexit( )来注册

注意printf() 加了换行一定会打印,但是不加换行不一定打印

2.1.1 代码

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

void f1(void)
{
	printf("f1 is callingn");//正在调用
	//关闭文件描述符
	//删除路径
	//.....
}

void f2(void)
{
	printf("f2 is callingn");//正在调用
}


int main()
{
	//退出处理函数
	atexit(&amp;f1);//像入栈(先声明的后执行),收尾工作
	atexit(&amp;f2);
	
	//注意printf() 加了换行一定会打印,但是不加换行不一定打印
	printf("abcd  ");//printf行输出,   标准缓冲区不满一行printf不输出
	
	//直接退出,什么都不管,慎用
	// _exit(0);
	
	//在退出之前,检查没有注册退出处理函数,如果有,会调用处理函数,并且检查IO缓冲区没有数据,如果有,会直接打印
	exit(0);	
}

使用exit(0); 结果看出,先打印缓冲区的东西,然后执行退出处理函数

使用_exit(0); 什么也不会打印直接退出

2.2 wait和waitpid

父进程如果需要可以使用 wait( )/waitpid( )来获得子进程正常退出的退出值, 当然,这两个函数还可以使得父进程阻塞等待子进程的退出

注意,所谓的退出状态不是退出值,退出状态包括了退出值。如果使用以上两个函数成 功获取了子进程的退出状态,则可以使用以下宏来进一步解析

2.2.1 代码

execl.c

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

int main()
{
    printf("hellon");
    pid_t pid = fork();//创建一个子进程
    if(pid == 0){
        //子进程
        execl("./son","./son","1.txt","2.txt","3.txt",NULL);//子进程那边设置了至少传4个参数,这个正确
        // execl("./son","./son","1.txt","2.txt",NULL);//这个调用子进程会参数异常退出

        //如果上面使用了execl函数那么这句话将不会输出
        printf("子进程的ID[%d],父进程的ID[%d]n",getpid(),getppid());//1744孤儿回收进程
    }

    if(pid>0){//父进程
        int status;//定义一个整形的退出状态值,4个字节
        wait(&amp;status);//用wait把退出值状态值传递进去,用来接收子进程的退出状态值
        
        //WEXITSTATUS(status)可以输出子进程的退出值
        printf("[退出值]%dn",WEXITSTATUS(status));
		printf("父进程的ID[%d],爷爷ID[%d]n",getpid(),getppid());
    }

    return 0;
}
son.c
#include<stdio.h>
#include<stdlib.h>

int main(int argc,char** argv)
{
    if(argc<4){
        printf("子进程温馨提示:参数不正确n");
        exit(2);//子进程参数不正确异常退出
    }
    for(int i=0;i<argc;i++){
        printf("%sn",argv[i]);
    }
    exit(99);//子进程正常退出
    return 0;
}

3. exec函数组

3.1 execl函数

代码和2.2.1一样

execl.c

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

int main()
{
    printf("hellon");
    pid_t pid = fork();//创建一个子进程
    if(pid == 0){
        //子进程
        execl("./son","./son","1.txt","2.txt","3.txt",NULL);//子进程那边设置了至少传4个参数,这个正确
        // execl("./son","./son","1.txt","2.txt",NULL);//这个调用子进程会参数异常退出

        //如果上面使用了execl函数那么这句话将不会输出
        printf("子进程的ID[%d],父进程的ID[%d]n",getpid(),getppid());//1744孤儿回收进程
    }

    if(pid>0){//父进程
        int status;//定义一个整形的退出状态值,4个字节
        wait(&amp;status);//用wait把退出值状态值传递进去,用来接收子进程的退出状态值
        
        //WEXITSTATUS(status)可以输出子进程的退出值
        printf("[退出值]%dn",WEXITSTATUS(status));
		printf("父进程的ID[%d],爷爷ID[%d]n",getpid(),getppid());
    }

    return 0;
}

3.2 execv函数

execv.c

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

int main()
{
    printf("hellon");
    pid_t pid = fork();//创建一个子进程
    if(pid == 0){
        //子进程
        char* arg[] = {"./son","1.txt","2.txt","3.txt",NULL};
        execv("./son",arg);//子进程那边设置了至少传4个参数,这个正确

        //如果上面使用了execl函数那么这句话将不会输出
        printf("子进程的ID[%d],父进程的ID[%d]n",getpid(),getppid());//1744孤儿回收进程
    }

    if(pid>0){//父进程
        int status;//定义一个整形的退出状态值,4个字节
        wait(&amp;status);//用wait把退出值状态值传递进去,用来接收子进程的退出状态值
        
        //WEXITSTATUS(status)可以输出子进程的退出值
        printf("[退出值]%dn",WEXITSTATUS(status));
		printf("父进程的ID[%d],爷爷ID[%d]n",getpid(),getppid());
    }

    return 0;
}

3.3 execlp函数

execlp.c

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

int main()
{
    printf("hellon");
    pid_t pid = fork();//创建一个子进程
    if(pid == 0){
        //子进程


        //execl也可以直接使用shell命令替换子进程的代码
        // execl("/bin/ls","ls","-l",NULL);

        //利用环境变量 PATH 来找寻指定执行文件
        execlp("ls","ls",NULL);


        //如果上面使用了execl函数那么这句话将不会输出
        printf("子进程的ID[%d],父进程的ID[%d]n",getpid(),getppid());//1744孤儿回收进程
    }

    if(pid>0){//父进程
        int status;//定义一个整形的退出状态值,4个字节
        wait(&amp;status);//用wait把退出值状态值传递进去,用来接收子进程的退出状态值
        
        //WEXITSTATUS(status)可以输出子进程的退出值
        printf("[退出值]%dn",WEXITSTATUS(status));
		printf("父进程的ID[%d],爷爷ID[%d]n",getpid(),getppid());
    }

    return 0;
}

原文地址:https://blog.csdn.net/m0_65554471/article/details/134709458

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_14337.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注