c - 系统调用 fork() 和 execv 函数

标签 c linux unix system-calls

我正在尝试使用此 C 代码连续运行两个可执行文件:

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

int main (int argc, char *argv[])
{
    fork();
    execv("./prcs1", &argv[1]); // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
    fork();
    execv("./prcs2", argv);
    printf("EXECV Failed\n");
}

程序在第一次 execv() 调用后退出,尽管有 fork ,它永远不会到达第二个 execv()。我试过在第一个 fork 之后调用 wait() 但我不确定它缺少什么。

知道为什么在子级退出后控制权没有返回给父级吗?

最佳答案

您需要了解 fork 和 execv 如何协同工作。

  • fork() 复制当前进程,返回 0 给子进程,childpid 给父进程
  • fork() 可能会失败,并在失败时返回 -1,检查一下
  • execv() 用新进程替换重复的父进程
  • 典型的 fork/exec 配对用新进程替换子进程
  • 您经常 fork 多个 child ,并希望他们同时运行,
  • 然而,你要求它们连续运行,也就是一个接一个
  • 因此,您需要等待第一个完成,然后再开始第二个
  • 因此你需要使用 wait() 的一些变体,下面的例子使用 waitpid() 来等待特定的 child

您需要用于退出的 stdlib(以防 execv 失败)和 errno,用于打印原因,

//I'm trying to run two executables consecutively using this c code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

你可能想检查你的 child 退出的原因(核心转储,信号,正常退出),所以我添加了这个功能,

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

//WIFEXITED(status) returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
//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.
//WIFSIGNALED(status) returns true if the child process was terminated by a signal.
//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.
//WCOREDUMP(status) returns true if the child produced a core dump.  This macro should only be employed if WIFSIGNALED returned true.  This macro is not specified in POSIX.1-2001 and is not available on some UNIX implementations (e.g., AIX, SunOS).  Only use this enclosed in #ifdef WCOREDUMP ... #endif.
//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 WUNTRACED or when the child is being traced (see ptrace(2)).
//WSTOPSIG(status) returns the number of the signal which caused the child to stop.  This macro should only be employed if WIFSTOPPED returned true.
//WIFCONTINUED(status) (since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT.
int
exitreason(pid_t cid, int status)
{
    if( WIFEXITED(status) )
    {
        printf("child %d terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().\n",cid);
        if( WEXITSTATUS(status) )
        {
        printf("child %d exit status %d.  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().\n",cid,WEXITSTATUS(status));
        }
    }
    if( WIFSIGNALED(status) )
    {
        printf("child %d process was terminated by a signal.\n",cid);
        if( WTERMSIG(status) )
        {
        printf("child %d signal %d that caused the child process to terminate.\n",cid,WTERMSIG(status));
        }
        if( WCOREDUMP(status) )
        {
        printf("child %d produced a core dump.  WCOREDUMP() is not specified in POSIX.1-2001 and is not available on some UNIX implementations (e.g., AIX, SunOS).  Only use this enclosed in #ifdef WCOREDUMP ... #endif.\n",cid);
        }
    }
    if( WIFSTOPPED(status) )
    {
        printf("child %d process was stopped by delivery of a signal; this is only possible if the call was done using WUNTRACED or when the child is being traced (see ptrace(2)).\n",cid);
        if( WSTOPSIG(status) )
        {
        printf("child %d number of the signal which caused the child to stop.\n",cid);
        }
    }
    if( WIFCONTINUED(status) )
    {
        printf("child %d process was resumed by delivery of SIGCONT.\n");
    }
}

这是你的程序,上面有注释,说明哪些代码部分由父级处理,哪些由子级处理。

int main (int argc, char *argv[])
{
    char proc1[] = "/bin/echo"; //"./prcs1";
    char proc2[] = "/bin/echo"; //"./prcs2";
    pid_t cid1, cid2, cidX;
    int status=0;
    int waitoptions = 0;
    //WNOHANG    return immediately if no child has exited.
    //WUNTRACED  also return if a child has stopped (but not traced via ptrace(2)).  Status for traced children which have stopped is provided even if this option is not specified.
    //WCONTINUED also return if a stopped child has been resumed by delivery of SIGCONT.
    int res;

    if( (cid1 = fork()) == 0 ) //child1
    {
        printf("in child1\n");
        if( (res = execv(proc1, &argv[1])) < 0 ) // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
        {
        printf("error: child1: %d exec failed %d\n", cid1, errno);
        printf("error: cannot execv %s\n",proc1);
        exit(91); //must exit child
        }
    }
    else if( cid1 > 0 ) //cid>0, parent, waitfor child
    {
        cidX = waitpid(cid1, &status, waitoptions);
        printf("child1: %d res %d\n", cid1, res);
        exitreason(cid1, status);
    }
    else //cid1 < 0, error
    {
        printf("error: child1 fork failed\n");
    }

    if( (cid2 = fork()) == 0 ) //child2
    {
        printf("in child2\n");
        if( (res = execv(proc2, &argv[1])) < 0 ) // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
        {
        printf("error: child2: %d exec failed %d\n", cid2, errno);
        printf("error: cannot execv %s\n",proc2);
        exit(92); //must exit child
        }
    }
    else if( cid2 > 0 ) //cid>0, parent, waitfor child
    {
        cidX = waitpid(cid2, &status, waitoptions);
        printf("child2: %d res %d\n", cid2, res);
        exitreason(cid2, status);
    }
    else //cid2 < 0, error
    {
        printf("error: child2 fork failed\n");
    }
}

关于c - 系统调用 fork() 和 execv 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19147386/

相关文章:

linux - 看书学习Linux内核

windows - 可在 Windows 和 Linux 上本地查看的格式化文档

linux - 让AppleScript发送电子邮件,然后通过shell脚本重新启动计算机?

linux - shell 脚本 telnet 在第一点跳过 while 循环

mysql - 在 spring security unix 中,即使详细信息正确,也重定向到authentication-failure-url

c - 如果我只是使用 wait() 一次等待 1 个 child 完成,我是否需要对 SIGCHLD 处理程序执行任何操作?

c - RRD具有高精度?

c - -1.#IND00 傅里叶级数和的结果

c - 释放函数本地指针并返回该指针

objective-c - 错误 : redefinition of ‘struct StructName’ message when compiling in Objective-C on Linux