精华内容
下载资源
问答
  • 若子进程先于父进程结束时,父进程调用wait()函数和不调用wait()函数会产生两种不同的结果: --> 如果父进程没有调用wait()和waitpid()函数,子进程就会进入僵死状态。 --> 如果父进程调用了wait()和waitpid...

    若子进程先于父进程结束时,父进程调用wait()函数和不调用wait()函数会产生两种不同的结果:

    --> 如果父进程没有调用wait()和waitpid()函数,子进程就会进入僵死状态。

    --> 如果父进程调用了wait()和waitpid()函数,就不会使子进程变为僵尸进程。

    这是为什么呢?现在我们来深入学习wait()函数和waitpid()函数。

     

    wait() 和 waitpid() 学习

    1、首先我们先看一下它们的函数原型:

    在终端输入命令:man 2 wait

    就会看到它的函数原型:

    NAME

           wait, waitpid, waitid - wait for process to change state

    SYNOPSIS

           #include <sys/types.h>

           #include <sys/wait.h>

           pid_t wait(int *status);

           pid_t waitpid(pid_t pid, int *status, int options);

           int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

    我们可以看到在2.6版本中新增叫了 waitid() 函数。

     

    2、wait() 和 waitpid() 的功能:

    1> wait()函数使父进程暂停执行,直到它的一个子进程结束为止,该函数的返回值是终止运行的子进程的PID,参数status所指向的变量存放子进程的退出码,即从子进程的main函数返回的值或子进程中exit()函数的参数。如果status不是一个空指针,状态信息将被写入它指向的变量。

    注意:进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait 就会收集这个子进程的信息, 并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

    2> 头文件sys/wait.h中定义了进程退出状态的宏。

    我们首先看下官方的解释

    a.WIFEXITED(status)     returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main() .

    翻译:

    WIFEXITED(status)  若子进程是正常结束时则返回一个非零值。即调用exit(3),_exit(3) 或从main()函数返回的值。

     

    b. WEXITSTATUS(status)   returns the exit status of the  child.   This  consists  of  the least  significant  8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or  as  the  argument for  a return  statement  in main().  This macro should only be employed if WIFEXITED returned true.

    翻译:

    WEXITSTATUS(status)    如果宏WIFEXIED返回值为非零值时,它返回子进程中exit或_exit参数中的低8位。

     

    c.WIFSIGNALED(status)  returns true if the child process was terminated by a signal.

    翻译:

    WIFSIGNALED(status)  若子进程异常终止则返回一个非零值。

     

    d. WTERMSIG(status)   returns the number of the signal that caused the  child  process  to terminate.  This macro should only be employed if WIFSIGNALED returned true.

    翻译:

    WTERMSIG(status)      如果宏WIFSIGNALED的返回值非零,则返回使子进程异常终止的信号编号。

     

    e.WIFSTOPPED(status)   returns true if the child process was stopped by delivery  of a signal;  this  is  only possible if the call was done using WUN‐TRACED or when the child is being traced (see ptrace(2)).

    翻译:

    WIFSTOPPED(status)  若子进程由于异常暂停,则返回一个非零值。当调用WUN‐TRACED或子进程被跟踪时这才时可能的。

     

    f. WSTOPSIG(status)    returns the number of the signal which caused the child to stop.This macro should only be employed if WIFSTOPPED returned true.

    翻译:

    WSTOPSIG(status)      如果宏WIFSTOPPED返回值非零,则返回使子进程暂停的信号编号。

     

    g.WIFCONTINUED(status)     (since  Linux  2.6.10)  returns  true  if  the child process wasresumed by delivery of SIGCONT.

    翻译:

    WIFCONTINUED(status)     (从2.6版本后)如果孩子进程通过SIGCONT恢复则返回一个非零值。

     

    3>waitpid() 函数

    (1).我们先来看一个waitpid()的经典例子:当我们下载了A软件的安装程序后,在安装快结束时它又启动了另外一个流氓软件安装程序B,当B也安装结束后,才告诉你所有安装都完成了。A和B分别在不同的进程中,A如何启动B并知道B安装完成了呢?可以很简单地在A中用fork启动B,然后用waitpid()来等待B的结束。

    (2).waitpid()也用来等待子进程的结束,但它用于等待某个特定进程结束。参数pid指明要等待的子进程的PID,参数status的含义与wait()函数中的status相同。options参数可以用来改变waitpid的行为,若将该参数赋值为WNOHANG,则使父进程不被挂起而立即返回执行其后的代码。

    (3).waitpid()函数中参数pid的取值

    还是先看下官方解释:

     The value of pid can be:

           < -1   meaning  wait  for  any  child process whose process group ID is equal to the absolute value of pid.

           -1     meaning wait for any child process.

           0      meaning wait for any child process whose  process  group  ID  is equal to that of the calling process.

           > 0    meaning  wait  for  the  child  whose process ID is equal to the value  of pid.

    翻译:

    pid的值可以为下己中情况:

      < -1  等待其组ID等于pid绝对值的任一子进程。

      =-1  等待任一子进程

      =0 等待其组ID等于调用进程的组ID的任一进程

      > 0  等待其进程ID等于pid的子进程退出

    (4).waitpid()函数的一个应用:

    如果想让父进程周期性地检查某个特定的子进程是否已经退出,可以用下面的方法:

    waitpid(child_pid, (int *) 0, WNOHANG);

    如果子进程尚未退出,它将返回0;如果子进程已经结束,则返回child_pid。调用失败时返回-1。失败的原因包括没有该子进程,参数不合法等。

     

    3、wait()和waitpid() 函数的区别

    (1).在一个子进程终止前,wait()使其调用者阻塞,而waitpid()有一个选项,可使调用者不阻塞。

    (2).waitpid()并不等待在其调用之后的第一个终止子进程,它有若干个选项,可以控制它所等待的进程。

    (3).对于wait(),其唯一的出错是调用进程没有子进程;对于waitpid(),若指定的进程或进程组不存在,或者参数pid指定的进程不是调用进程的子进程都可能出错。

    (4).waitpid()提供了wait()没有的三个功能:一是waitpid()可等待一个特定的进程;二是waitpid()提供了一个wait()的非阻塞版本(有时希望取的一个子进程的状态,但不想使父进程阻塞,waitpid() 提供了一个这样的选择:WNOHANG,它可以使调用者不阻塞);三是waitpid()支持作业控制。

    (5).wait(&status) 的功能就等于 waitpid(-1, &status, 0);

     

    函数实例: 有时希望取的一个子进程的状态,但不想使父进程阻塞,waitpid() 提供了一个这样的选择:WNOHANG,它可以使调用者不阻塞

    #include <sys/wait.h>
    #include <unistd.h>
    #include <stdio.h>
    
    int main()
    {
    	pid_t pr, pc;
    
    	do
    	{
    		pr = waitpid(pc, NULL, WNOHANG);
    
    		if (pr == 0)
    		{
    			printf("No child exited\n");
    			sleep(1);
    		}
    
    	}
    	while (pr == 0);
    
    	if (pr == pc)
    	{
    		printf("successfully get child %d\n", pr);
    	}
    	else
    	{
    		printf("some error occured\n");
    	}
    
    	return 0;
    }
    
    

     

    总结

    无论进程是否正常终止,内核都会向其父进程发送SIGCHLD 信号,当调用wait或waitpid函数时

    (a) 如果所有的子进程都在run, 可以阻塞父进程。

    (b) 如果子进程终止,则wait立即返回子进程终止状态。

    (c) 如果没有子进程在运行, 立即返回error。

     

    4、函数实现:

    函数实例1.(先看一个简单的实例,看看进程调用wait()函数后是如何执行的?)

    #include<stdio.h>
    #include<sys/types.h>
    #include<sys/wait.h>
    #include<unistd.h>
    #include<stdlib.h>
    
    int main()
    {
    	pid_t child;
    	int i;
    
    	child = fork();
    
    	if (child < 0)
    	{
    		printf("create failed!\n");
    		exit(1);
    	}
    	else if (0 == child)
    	{
    		printf("this is the child process pid= %d\n", getpid());
    
    		for (i = 0; i < 5; i++)
    		{
    			printf("this is the child process print %d !\n", i + 1);
    		}
    
    		printf("the child end\n");
    	}
    	else
    	{
    		printf("this is the father process, ppid=%d\n", getppid());
    		printf("father wait the child end\n");
    		wait(&child);
    		printf("father end\n");
    	}
    }

    函数经过编译:

    gcc wait.c -o wait
    ./wait

    函数执行结果:

    this is the father process, ppid=3303

    father wait the child end

    this is the child process pid= 3356

    this is the child process print 1 !

    this is the child process print 2 !

    this is the child process print 3 !

    this is the child process print 4 !

    this is the child process print 5 !

    the child end

    father end

     

    说明:

    从上面的程序我们可以深入的了解wait() 函数的执行过程:

    当父进程调用wait()函数后被挂起等待,直到子进程结束为止。

     

    函数实例2(现在我们在通过一个实例,来深入了解wait()函数的执行过程)

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    int main()
    {
    	pid_t pid;
    	char *msg;
    	int i;
    	int exit_code;
    
    	printf("tiger study how to get exit code\n");
    	pid = fork();
    
    	if (pid == 0)		/* 子进程 */
    	{
    		msg = "child process is running";
    		i = 5;
    		exit_code = 37;
    	}
    	else if (pid > 0)	/* 父进程 */
    	{
    		exit_code = 0;
    	}
    	else
    	{
    		perror("process creation failed\n");
    		exit(1);
    	}
    
    	if (pid > 0) /* 父进程 */
    	{
    		int status;
    		pid_t child_pid;
    		child_pid = wait(&status);
    
    		printf("child process has exited, pid=%d\n", child_pid);
    		if (WIFEXITED(status))
    		{
    			printf("child exited with code %d\n", WEXITSTATUS(status));
    		}
    		else
    		{
    			printf("child exited abnormally\n");
    		}
    	}
    	else /* 子进程 */
    	{
    		while (i-- > 0)
    		{
    			puts(msg);
    			sleep(1);
    		}
    	}
    
    }

     

    函数进过编译后:

    $ gcc wait1.c -o wait1
    $ ./wait1

    函数执行结果 :

    tiger study how to get exit code

     child process is running

     child process is running

     child process is running

     child process is running

     child process is running

    child process has exited,pid = 3816

    child exited with code 0

     

    说明:

    父进程调用wait()函数后被挂起(我们可以再开一个终端,输入命令:ps aux,可以看到父进程的执行结果为S)直到子进程结束。子进程结束后,wait()函数返回刚刚结束运行的子进程的pid,宏WEXITSTATUS获取子进程的退出码。

     


     

    注意

    如果调用 wait() 的进程没有已终止的子进程,不过有一个或多个子进程仍在运行,那么 wait 将阻塞到现有子进程第一个终止为止。

    waitpid 函数就等待哪个进程以及是否阻塞给了我们更多控制。首先,pid 参数允许我们指定想等待的进程ID,值-1表示等待第一个终止的子进程。其次,options 参数允许我们指定附加选项。最常用的选项是 WNOHANG,它告知内核在没有已终止子进程时不要阻塞。

     

     

    参考:

    http://www.tc5u.com/linux_unix/1635564.htm

    http://blog.163.com/libo_5/blog/static/15696852010324287748/

    转载于:https://www.cnblogs.com/52php/p/5684575.html

    展开全文
  • 一、结束进程: 我们可以通过exit()或者_exit()函数来结束当前进程。 (一) 所需头文件: #include &amp;amp;lt;stdlib.h&amp;amp;gt; 函数: void exit(int value); 功能: 结束调用此函数的进程 ...

    一、结束进程:
    我们可以通过exit()或者_exit()函数来结束当前进程。
    (一)

    • 所需头文件:
    #include <stdlib.h>
    
    • 函数:
    void exit(int value);
    
    • 功能:

    结束调用此函数的进程

    • 参数:

    status:返回父进程的参数(低8为有效)

    • 返回值:


    (二)

    • 所需头文件:
    #include <unistd.h>
    
    • 功能:

    结束调用此函数的进程

    • 参数:

    status:返回父进程的参数(低8为有效)

    • 返回值:


    注意:exit()和_exit()函数功能和用法是一样的,无非是所包含的头文件不一样,一个是库函数,一个是系统函数
    区别如下:
    在这里插入图片描述
    我们可以通过下面这个例子来验证:
    test.c

    #include<stdio.h>
    #include <stdlib.h>
    
    int main()
    {
      printf("hello world!");
      exit(0);
      while(1);
      return 0;
    }
    

    运行结果:在这里插入图片描述
    test1.c

    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    {
      printf("hello world!");
      _exit(0);
      while(1);
      return 0;
    }
    

    运行结果:
    在这里插入图片描述
    注意:这里printf中的内容不能带\n,\n会刷新。
    二、等待进程结束:
    当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号,相当于告诉父亲哪个子进程挂了,父进程通过wait()或waitpid()函数等待子进程结束,获取子进程结束时的状态,同时回收资源。
    wait()和waitpid()函数的功能一样,区别在于,wait()函数会阻塞,waitpid()可以设置不阻塞,waitpid()还可以指定等待哪个子进程结束。
    (一)

    • 所需头文件:
    #include <sys/types.h>
    #include <sys/wait.h>
    
    • 函数:
    pid_t wait(int* status);
    
    • 功能:
    • 等待任意一个子进程结束,如果任意一个子进程结束了,此函数就回收该子进程的资源
    • 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件、占用的内存等。但是仍然会保留一定的信息,这些信息主要指进程控制块的信息(包括进程号、退出状态、运行时间等)。
    • 调用wait()函数的进程会挂起(阻塞),直到它的一个子进程退出或者收到一个不能被忽视的信号时才被唤醒(继续往下执行)
    • 若调用进程没有子进程,则函数立即返回,若它的子进程已经结束,该函数同样会立即返回,并且回收该子进程的资源。

    总言之:wait()函数的主要功能为回收已经结束子进程的资源

    • 参数:
    • status:进程退出时的状态信息。
    • 如果参数status的值不是NULL,wait()就会把子进程退出时的状态取出并存入其中,这是一个整数值(int),指出了子进程时正常退出还是被异常结束的。
    • 这个退出在一个int中包含了多个字段,不能直接使用,需要使用宏定义取出其中每个字段。
    WIFEXITED(status);//如果子进程是正常终止的,取出的字段非0
    
    WEXITSTATUS(status);//返回子进程的退出状态,退出状态保存在status变量的8~16位,在用此宏前先用WIFEXITED判断子进程是否正常退出,正常退出才可以使用此宏。
    
    • 返回值
    • 成功:已经结束子进程的进程号
    • -1

    从本质上讲:系统调用waitpid()和wait()的作用是完全相同的,但waitpid()多出了两个有用户可控制的参数pid和options,从而可以灵活使用。
    (二)

    • 函数:
    pid_t waitpid(pid_t pid,int* status,int options);
    
    • 功能:

    等待子进程终止,如果子进程终止了,此函数回收子进程的资源。

    • 参数:
    • pid:参数pid的值有以下几种类型:
      (1)pid>0:等待ID等于pid的子进程
      (2)pid=0:等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会等待
      (3)pid=-1:等待任一子进程,此时waitpid和wait一样
      (4)pid<-1:等待指定进程组中的任一子进程,这个进程组的ID等于pid的绝对值
    • status:进程退出时的状态信息,和wait()用法一样
    • options:options提供了一些二外的选项来控制waitpid()
      (1) 0:同wait(),阻塞父进程,等待子进程退出。
      (2) WNOHANG:没有任何已经结束的子进程,则立即返回
      (3) WUNTRACED:如果子进程暂停了则此函数马上返回,并且不予理会子进程的结束状态。
    • 返回值:waitpid()的返回值比wait()稍微复杂一些,三种情况:
      (1)当正常返回时,返回收集到的已经结束的子进程的进程号。
      (2)如果设置了WNOHANG,而调用中waitpid()发现没有已退出的子进程可等待,则返回0
      (3)如果调用出错,则返回-1,这是error会被设置成相应的值以示错误存在。
      测试例子:
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/wait.h>
    #include <unistd.h>
    int main(int argc,char* argv[])
    {
      pid_t pid;
      pid = fork();
      if(pid<0)
      {
        perror("fork error");
        exit(0);
      }
      else if(pid == 0)
      {
        //子进程
        int i;
        for(i = 0;i<5;++i)
        {
          printf("this is son process\n");
          sleep(1);
        }
    
        _exit(2);
      }
      else 
      {
        //父进程
        int status = 0;
        wait(&status);
        if(WIFEXITED(status) != 0)
        {
          printf("son process return %d\n",WEXITSTATUS(status));
        }
        printf("this is father process\n");
      }
      return 0;
    }
    

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

    展开全文
  • Linux进程(创建进程、等待进程结束、退出进程) 1.创建进程 #include <sys/types.h> #include <unistd.h> pid_t fork(void); fork()函数用来创建一个进程,创建成功返回0,失败返回-1。 实例 #include...

    Linux进程(创建进程、等待进程结束、退出进程)

    1.创建进程

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

    fork()函数用来创建一个进程,创建成功返回0,失败返回-1。
    实例

    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        pid_t pid;
        pid=fork();
        if(-1==pid)
        {
            printf("Error to create new process!\n");
            return -1;
        }
        else if(pid==0)
        {
            printf("Child process!\n");
        }
        else
        {
            printf("Parent process! Child process ID:%d",pid);
        }
        return 0;
    }
    

    2.等待进程结束

    #include <sys/types.h>
    #include <sys/wait.h>
    pid_t waitpid(pid_t pid,int *status,int options);
    

    waitpid()返回值:
    ①<-1:等待所有其进程组表示等于pid绝对值的子进程;
    ②-1:等待任何子进程;
    ③0:等待任何其组标识等于调用进程组标识的进程;
    ④>0:等待其进程标识等于pid的进程。
    status表示子进程的返回状态,option默认为0或者设置其他选项,这里不做解释。

    实例

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    int main()
    {
        pid_t pid,pid_wait;
        int status;
        pid=fork();
        if(-1==pid)
        {
            printf("Error to create new process!\n");
            return 0;
        }
        else if(pid==0)
        {
            printf("Chile process!\n");
        }
        else
        {
            printf("Parent process!Child process ID:%d\n",pid);
            pid_wait=waitpid(pid,&status,0);
            printf("Child process %d returned!\n",pid_wait);
        }
        return 0;
    }
    

    3.退出进程

    #include <stdlib.h>
    int atexit(void (*function)(void));
    int on_exit(void (*function)(int,void*),void *arg);
    void exit(int status);
    
    #include <unistd.h>
    void _exit(int status);
    

    exit()是退出当前进程,释放进程占用资源;_exit()也是退出当前进程,不释放进程占用资源。
    atexit()和on_exit()是程序退出时调用用户代码。

    实例

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    void bye()
    {
        printf("That was all,forks\n");
    }
    
    void bye1()
    {
        printf("This is the first fork\n");
    }
    
    int main()
    {
        int i;
        i=atexit(bye);
        if(i!=0)
        {
            fprintf(stderr,"cannot set exit function bye()!\n");
            return EXIT_FAILURE;
        }
        i=atexit(bye1);
        if(i!=0)
        {
            fprintf(stderr,"cannot set exit function bye1()!\n");
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }
    

    bye1()会被先执行,bye()后执行。

    不积跬步无以至千里。

    展开全文
  • 当一个进程正常或异常终止时,内核就向其父进程发送 SIGCHLD 信号,相当于告诉父亲他哪个儿子挂了,而父进程可以通过 wait() 或 waitpid() 函数等待进程结束,获取子进程结束时的状态,同时回收他们的资源(相当于...

    结束进程

    首先,我们回顾一下 C 语言中 continue, break, return 的作用:

    continue: 结束本次循环

    break: 跳出整个循环,或跳出 switch() 语句

    return: 结束当前函数


    而我们可以通过 exit() 或 _exit() 来结束当前进程。


    所需头文件:

    #include <stdlib.h> 


    void exit(int value);

    功能:

    结束调用此函数的进程。

    参数:

    status:返回给父进程的参数(低 8 位有效),至于这个参数是多少根据需要来填写。

    返回值:


    所需头文件:

    #include <unistd.h>


    void _exit(int value);

    功能:

    结束调用此函数的进程。

    参数:

    status:返回给父进程的参数(低 8 位有效),至于这个参数是多少根据需要来填写。

    返回值:


    exit() 和 _exit() 函数功能和用法是一样的,无非时所包含的头文件不一样,还有的区别就是:exit()属于标准库函数,_exit()属于系统调用函数。


    下面的例子验证调用 exit() 函数,会刷新 I/O 缓冲区(关于缓冲区的更多详情,请看《浅谈标准I/O缓冲区》):

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
    	printf("hi, mike, you are so good"); // 打印,没有换行符"\n"
    	
    	exit(0);      // 结束进程,标准库函数,刷新缓冲区,printf()的内容能打印出来
    	// _exit(0);  // 结束进程,系统调用函数,printf()的内容不会显示到屏幕
    	
    	while(1);	// 不让程序结束
    
    	return 0;
    }


    运行结果如下:



    上面的例子,结束进程的时候改为调用 _exit(),代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
    	printf("hi, mike, you are so good"); // 打印,没有换行符"\n"
    	
    	//exit(0);      // 结束进程,标准库函数,刷新缓冲区,printf()的内容能打印出来
    	_exit(0);  // 结束进程,系统调用函数,printf()的内容不会显示到屏幕
    	
    	while(1);	// 不让程序结束
    
    	return 0;
    }

    printf() 的内容是不会显示出来的,运行结果如下:



    接下来,我们一起验证一下结束函数( return )和结束进程( exit() )的区别。


    测试代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    void fun()
    {
    	sleep(2);
    	
    	return;  // 结束 fun() 函数
    	
    	while(1);
    }
    
    
    int main(int argc, char *argv[])
    {
    	fun();
    	
    	printf("after fun\n");
    	
    	while(1);	// 不让程序结束
    
    	return 0;
    }
    

    运行结果如下:



    通过上面的运行结果得知,return 的作用只是结束调用 return 的所在函数,只要这个函数不是主函数( main() ),只要主函数没有结束,return 并不能结束进程


    我们将上面例子 fun() 里的 return 改为 exit():

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    void fun()
    {
    	sleep(2);
    	
    	exit(0);  // 结束当前进程
    	
    	while(1);
    }
    
    int main(int argc, char *argv[])
    {
    	fun();
    	
    	printf("after fun\n");
    	
    	while(1);	// 不让程序结束
    
    	return 0;
    }



    exit() 是可以结束 fun() 所在的进程,即可让程序结束运行,结果图如下:



    等待进程结束

    当一个进程正常或异常终止时,内核就向其父进程发送 SIGCHLD 信号,相当于告诉父亲他哪个儿子挂了,而父进程可以通过 wait() 或 waitpid() 函数等待子进程结束,获取子进程结束时的状态,同时回收他们的资源(相当于,父亲听听死去儿子的遗言同时好好安葬它)。


    wait() 和 waitpid() 函数的功能一样,区别在于,wait() 函数会阻塞,waitpid() 可以设置不阻塞,waitpid() 还可以指定等待哪个子进程结束。


    所需头文件:

    #include <sys/types.h>

    #include <sys/wait.h>


    pid_t wait(int *status);

    功能:

    等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收该子进程的资源。


    在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要主要指进程控制块的信息(包括进程号、退出状态、运行时间等)。


    调用 wait() 函数的进程会挂起(阻塞),直到它的一个子进程退出或收到一个不能被忽视的信号时才被唤醒(相当于继续往下执行)。


    若调用进程没有子进程,该函数立即返回;若它的子进程已经结束,该函数同样会立即返回,并且会回收那个早已结束进程的资源。


    所以,wait()函数的主要功能为回收已经结束子进程的资源。


    参数:

    status: 进程退出时的状态信息。


    如果参数 status 的值不是 NULL,wait() 就会把子进程退出时的状态取出并存入其中,这是一个整数值(int),指出了子进程是正常退出还是被非正常结束的。


    这个退出信息在一个 int 中包含了多个字段,直接使用这个值是没有意义的,我们需要用宏定义取出其中的每个字段


    下面我们来学习一下其中最常用的两个宏定义,取出子进程的退出信息:

    WIFEXITED(status)

    如果子进程是正常终止的,取出的字段值非零。

    WEXITSTATUS(status)

    返回子进程的退出状态,退出状态保存在 status 变量的 8~16 位。在用此宏前应先用宏 WIFEXITED 判断子进程是否正常退出,正常退出才可以使用此宏。


    返回值:

    成功:已经结束子进程的进程号

    失败:-1


    从本质上讲,系统调用 waitpid() 和 wait() 的作用是完全相同的,但 waitpid() 多出了两个可由用户控制的参数 pid 和 options,从而为我们编程提供了另一种更灵活的方式。


    pid_t waitpid(pid_t pid, int *status, int options);

    功能:

    等待子进程终止,如果子进程终止了,此函数会回收子进程的资源。

    参数:

    pid: 参数 pid 的值有以下几种类型:

    pid > 0

    等待进程 ID 等于 pid 的子进程。

    pid = 0

    等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid 不会等待它。

    pid = -1

    等待任一子进程,此时 waitpid 和 wait 作用一样。

    pid < -1

    等待指定进程组中的任何子进程,这个进程组的 ID 等于 pid 的绝对值。


    status: 进程退出时的状态信息。和 wait() 用法一样。


    options: options 提供了一些额外的选项来控制 waitpid()。

    0

    同 wait(),阻塞父进程,等待子进程退出。

    WNOHANG

    没有任何已经结束的子进程,则立即返回。

    WUNTRACED

    如果子进程暂停了则此函数马上返回,并且不予以理会子进程的结束状态。(由于涉及到一些跟踪调试方面的知识,加之极少用到,这里就不多费笔墨了,有兴趣的读者可以自行查阅相关材料)

    返回值:

    waitpid() 的返回值比 wait() 稍微复杂一些,一共有 3 种情况:


    当正常返回的时候,waitpid() 返回收集到的已经子进程的进程号;


    如果设置了选项 WNOHANG,而调用中 waitpid() 发现没有已退出的子进程可等待,则返回 0;


    如果调用中出错,则返回 -1,这时 errno 会被设置成相应的值以指示错误所在,如:当 pid 所对应的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid() 就会出错返回,这时 errno 被设置为 ECHILD;


    测试例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main(int argc, char *argv[])
    {
    	pid_t pid;
    	
    	pid = fork(); // 创建进程
    	if( pid < 0 ){ // 出错
    		perror("fork");
    		exit(0);
    	}
    	
    	if( pid == 0 ){// 子进程
    		int i = 0;
    		for(i=0;i<5;i++)
    		{
    			printf("this is son process\n");
    			sleep(1);
    		}
    		
    		_exit(2); // 子进程退出,数字 2 为子进程退出的状态
    		
    	}else if( pid > 0){ // 父进程
    		
    		int status = 0;
    		
    		// 等待子进程结束,回收子进程的资源
    		// 此函数会阻塞
    		// status 某个字段保存子进程调用 _exit(2) 的 2,需要用宏定义取出
    		wait(&status); 
    		// waitpid(-1, &status, 0); // 和 wait() 没区别,0:阻塞
    		// waitpid(pid, &status, 0); // 指定等待进程号为 pid 的子进程, 0 阻塞
    		// waitpid(pid, &status, WNOHANG); // WNOHANG:不阻塞
    		if(WIFEXITED(status) != 0){ // 子进程是否正常终止
    			printf("son process return %d\n", WEXITSTATUS(status));
    		}
    		
    		printf("this is father process\n");	
    	}
    	
    	return 0;
    }
    

    运行结果如下:



    本教程示例代码下载请点此。

    展开全文
  • Linux父进程等待进程结束

    千次阅读 2013-11-19 20:57:20
    进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出。如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一...
  • 结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳出 switch() 语句 return: 结束当前函数 而我们可以通过 exit() 或 _exit() ...
  • 结束进程首先,我们回顾一下 C 语言中 continue, break, return 的作用:continue: 结束本次循环break: 跳出整个循环,或跳出 switch() 语句return: 结束当前函数而我们可以通过 exit() 或 _exit() 来结束当前进程。...
  • 结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳出 switch() 语句 return: 结束当前函数 而我们可以通过 exit() 或 _exit() 来结束...
  • 结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳出 switch() 语句 return: 结束当前函数 而我们可以通过 exit() 或 _exit() 来...
  • 如果要安排父进程在子进程结束之后才结束。可以调用wait函数。函数说明pid_t wait(int * stat_loc)包含的头文件: #include #include 返回值:子进程的PID参数:如果stat_loc不是一个空指针,状态信息将被写入它指向...
  • 这个是改进后的,之前waitForFinished()阻塞有点问题,这个是获取结束进程的退出状态后执行 .h文件 #ifndef INFACETEST_H #define INFACETEST_H #include <QMainWindow> #include <QComboBox> #...
  • linux c 等待所有子进程结束

    千次阅读 2013-03-08 20:20:04
    当子进程结束时,它会向父进程发送SIG_CHLD信号,然后父进程使用wait waitpid waittid函数来捕获某一子进程的退出状态。当需要等待所有子进程全部退出时,我们可以设置SIG_CHLD为SIG_IGN,然后使用wait来阻塞直到...
  • 若子进程先于父进程结束时,父进程调用wait()函数和不调用wait()函数会产生两种不同的结果: --如果父进程没有调用wait()和waitpid()函数,子进程就会进入僵死状态。 --如果父进程调用了wait()和waitpid()函数,就...
  • 上一节最后我们说到若子进程先于父进程结束时,父进程调用wait()函数和不调用wait()函数会产生两种不同的结果: --如果父进程没有调用wait()和waitpid()函数,子进程就会进入僵死状态。 --如果父进程调用...
  • pid_t r_wait(int * stat_loc) { int revalue; while(((revalue = wait(stat_loc)) == -1) && (errno == EINTR));//如果等待的过程中被一个不可...服务退出之前父进程等待进程的调用方法: while(r_wait(NULL)
  • 进程如果不等待进程退出,在子进程之前就结束了自己的 “生命” ,此时的子进程便称为 孤儿进程Linux 系统为避免存在过多孤儿进程,设置了 init 进程收留孤儿进程,使其变为 孤儿进程的父进程。 init 进程...
  • Linux进程7.进程等待

    2020-10-28 20:06:03
    他需要父进程来为它收尸,如果父进程没有安装SIGCHLD信号处理函数,调用wait()或者waitpid()等待进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态。如果这时父进程结束了,那么init进程会自动接手这个子...
  • linux C进程 进程等待wait与waitpid函数

    千次阅读 2017-11-26 12:20:04
    1. 孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程变为init进程 。 2. 僵尸进程:子进程终止了,父进程尚未回收子进程,子进程残留资源(PCB)存放于内核中,子进程变成僵尸(Zombie)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 844
精华内容 337
关键字:

linux等待进程结束

linux 订阅