UNIX中的进程何时终止?

时间:2015-09-25 16:22:48

标签: unix process fork

我对UNIX中进程的结束感到困惑。 UNIX中的进程何时终止?我们是否必须写exit(0)来终止进程?在我看来 - 不,但我无法弄清楚这两段代码之间的区别。

pid_t pid=fork();
if(pid < 0)
{
             perror("Fork error\n");
             return 1;  
}
else if (pid==0) /* child */
{
             //Do some operations here
}
else
{
            wait(NULL);
            //Do some operations
}

pid_t pid=fork();
if(pid < 0)
{
                 perror("Fork error\n");
                 return 1;  
 }
 else if (pid==0) /* child */
 {
                 //Do some operations here
                 exit(0);
 }
 else
 {
                wait(NULL);
                //Do some operations here
 }

可能我们只需exit(0) wait()函数。在这种情况下,如果我们wait()未完成exit(0)会发生什么  之前?

1 个答案:

答案 0 :(得分:2)

POSIX

请参阅exit()

  

终止流程

     

重要的是,无论过程是否_exit()(可能间接通过exit())或由于信号或其他原因而终止,都会发生所述过程终止的后果。

     

[...]

     

根据ISO C标准的要求,使用main()的返回与使用返回值调用exit()具有相同的行为(除语言范围问题之外)。到达main()函数的末尾与调用exit(0)具有相同的行为。

另见wait()。正常终止:

  

如果由于子进程的状态可用而返回wait()waitpid(),则这些函数将返回等于子进程的进程ID的值。 [...]存储在stat_loc所指向的位置的值应为0当且仅当返回的状态来自已终止的子进程,该进程以下列方式之一终止:

     
      
  • 该流程从0返回main()
  •   
  • 此过程名为_exit()exit(),状态参数为0
  •   
  • 该进程已终止,因为进程中的最后一个线程已终止。
  •   

指定的终止原因列表:

  
      
  • WIFEXITED(stat_val)

         

    如果正常终止的子进程返回状态,则计算为非零值。

  •   
  • WIFSIGNALED(stat_val)

         

    如果由于收到未捕获的信号而终止的子进程返回状态,则评估为非零值(参见<signal.h>)。

  •   

及各自的状态信息:

  
      
  • WEXITSTATUS(stat_val)

         

    如果WIFEXITED(stat_val)的值不为零,则此宏计算为子进程传递给_exit()exit()的状态参数的低8位,或者子进程从main()返回的值。

  •   
  • WTERMSIG(stat_val)

         

    如果WIFSIGNALED(stat_val)的值不为零,则此宏将评估导致子进程终止的信号编号。

  •   

摘要

总而言之,POSIX提到了如何终止进程的两种方式:

  • 进程可以自行终止,如果它调用exit()_exit()或从main()返回,或者进程的最后一个线程终止;
  • 进程可以被信号杀死(由内核或其他进程或进程本身发送)。

线程

如果您需要阻止所有线程在main()返回时终止,请参阅"Is it OK to call pthread_exit from main?"

在孩子中使用exit()

  

在这种情况下,如果我们在没有wait()之前完成exit(0)会发生什么?

fork()重复当前进程,父进程和子进程在fork()返回时从同一点继续执行。

考虑以下示例:

int main() {
    if (fork() == 0) { /* child */
        foo();
    }
    else { /* parent */
        wait(NULL);
    }

    bar(); /* called in parent in child */
    return 0; /* or exit(0) */
}

在此示例中,子项不会在其exit()分支中调用if,因此在调用foo()后,它会调用bar()而不是从main()返回子进程终止。换句话说,孩子和家长都在这里打电话bar()

通常这不是你想要的,而是你写的:

int main() {
    if (fork() == 0) { /* child */
        foo();
        exit(0);
    }
    else { /* parent */
        wait(NULL);
    }

    bar(); /* called only in parent */
    return 0;
}

在这种情况下,孩子在致电foo()后立即退出,以便bar()未在孩子中召唤。