启动execlp作为后台进程

时间:2014-07-07 08:22:18

标签: c exec

我尝试使用execlp启动程序,继续执行该程序。然后控制回来。

这是我在SO的一些研究后所做的。

pid_t child;
pid_t sid;  
child = fork();
if (!child) {
    sid = setsid();
    if(!sid) {   
        exit(1);
    }
    execlp(RUN_EXE, RUN_EXE, SPEC_RUN.run_args[j], (char *)0);
}

但我在execlp之后无法打印任何内容。 execlp对我来说正常。

我需要做些什么让shell返回?

2 个答案:

答案 0 :(得分:1)

成功后,execve(2)系统调用不会返回(只有在失败时才会返回)。 execlp(3)包装器也是如此。

您通常希望在进程中execve。而fork(2)可能会失败。您通常应在fork之前致电fflush(3)。所以代码:

fflush(NULL);
pid_t p = fork();
if (p < 0) { perror("fork"); exit (EXIT_FAILURE); };
if (p == 0) { /* child process */
    execlp(RUN_EXE, RUN_EXE, SPEC_RUN.run_args[j], (char *)0);
    perror("execlp");
    fflush(NULL);
    _exit(EXIT_FAILURE);
}
/// continue in the parent process
printf("child process is %d\n", (int)p);

别忘了wait孩子,例如使用waitpid(2)

另请参阅system(3)popen(3)daemon(3)posix_spawn和阅读Advanced Linux Programming(其中有一章很好解释这些内容)。

另外,使用strace(1)了解事情是如何运作的。

答案 1 :(得分:1)

如果我理解正确,你想创建一个子流程,在该流程中运行一个程序,然后等待它完成。当直接使用系统原语时,这三个步骤中的每一步都是在Unix上自己的操作。您已了解fork()execlp();第三步,等待子进程完成,由waitpid()及其亲属完成。

在Basile写的基础上,这是缺失的部分:

#define _POSIX_C_SOURCE 200809L /* strsignal */
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

void run_program(void)
{
    int status;
    pid_t pid;

    fflush(0);

    /* create the subprocess */
    pid = fork();
    if (p < 0) { /* fork failed */
        perror("fork");
        exit(1);
    }

    /* in the child only, execute a program */
    if (p == 0) {
        execlp(RUN_EXE, RUN_EXE, SPEC_RUN.run_args[j], (char *)0);
        /* If execlp returns, it failed.  It is unsafe to call `exit` if this
           happens; you must instead use `_exit`.  This means you have to flush
           output manually. */
        fprintf(stderr, "execlp: %s: %s\n", RUN_EXE, strerror(errno));
        fflush(stderr);
        _exit(1);
    }

    /* in the parent, wait for the child to finish */
    if (waitpid(pid, &status, 0) != pid) {
        perror("waitpid");
        exit(1);
    }

    /* decode and report any failure of the child */
    if (WIFEXITED(status)) {
        if (WEXITSTATUS(status) == 0)
            return; /* success! */

        fprintf(stderr, "%s: unsuccessful exit %d\n",
                RUN_EXE, WEXITSTATUS(status));
        exit(1);
    }
    if (WIFSIGNALED(status)) {
        fprintf(stderr, "%s: %s%s\n",
                RUN_EXE,
                strsignal(WTERMSIG(status)),
                WCOREDUMP(status) ? " (core dumped)" : "");
        exit(1);
    }
    fprintf(stderr, "%s: impossible exit status %04x\n",
            RUN_EXE, status);
    exit(1);
}

...如果这看起来像你想要处理的巨大头发,你应该考虑使用更高级别的库函数system()和/或popen()代替。他们有自己的缺陷 - 最重要的是,他们经历/bin/sh,这通常不是你想要的 - 但在简单的情况下,它们更容易使用。