1

我正在玩信号、fork 和 execve,并且我编写了一个玩具程序,用于fork()创建一个调用另一个玩具程序的子进程。然后父级设置警报以在一定秒数后终止该功能。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <signal.h>

pid_t childPid;

pid_t Fork()
{
    pid_t pid;

    if ((pid = fork()) < 0)
        printf("Error:\n");
    return pid;
}

void killhandler(int sig)
/*This will be called when we receive a SIGALRM*/
{
    int status;
    printf("\nAssassin: *ksh* Received order to kill process: %d\n", (int)childPid);
    if (!(status = kill(childPid, SIGKILL))) {
        printf("Assassin: Clean and discreet. My work here is done. *ksh*\n");
    } else {
        printf("Assassin: He got away!\n");
    }
}

void forkyMcFork()
{
    pid_t pid;
    int status;
    /*Generate information for new program*/
    char* argv[] = {"problem5", "Hello"};
    char* envp[] = {"PANTS=JEANS"};
    char* func = "problem5";

    /* Create child process, child process calls executable "problem5" */
    if ((pid = Fork()) == 0) {
        printf("Child: I am a child! Woohoo!\n");
        if (execve(func, argv, envp) < 0)
            printf("Child: error, %s not found\n", func);
        while(1);
    }
    else {
        /* Parent process sets alarm, then prints a message depending on exit status*/
        childPid = pid;
        alarm(3);
        printf("Parent: I am the parent!\n");
        waitpid(-1, &status, 0);
        if (!WIFEXITED(status)) {
            printf("Parent: Oh no, what happened to my baby!!!\n");
            exit(0);
        } else {
            printf("Parent: Child came home without any problems.\n");
        }
    }
}

int main(int argc, char const *argv[])
{
    signal(SIGALRM, killhandler);
    forkyMcFork();
    return 0;
}

这是奇怪的部分:如果我声明该函数forkyMcFork()不带参数,然后alarm()手动设置参数,那么它就像我期望的那样工作:子进程启动problem5,它要求用户输入一些输入,然后在 3秒,killhandler运行,找到子进程并杀死它:

$ ./forkfun
Parent: I am the parent!
Child: I am a child! Woohoo!
Please type name. If finished press enter: Haha
Please type name. If finished press enter: 
Assassin: *ksh* Received order to kill process: 42409
Assassin: Clean and discreet. My work here is done. *ksh*
Parent: Oh no, what happened to my baby!!!
$ 

但是,如果我改为声明forkyMcFork(int secs)然后使用,则找不到alarm(secs)应该由子程序中的语句调用的外部程序。execve()警报按预期运行,因此在几秒钟后,子进程被取消。

这是非工作代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <signal.h>

pid_t childPid;

pid_t Fork()
{
    pid_t pid;

    if ((pid = fork()) < 0)
        printf("Error:\n");
    return pid;
}

void killhandler(int sig)
/*This will be called when we receive a SIGALRM*/
{
    int status;
    printf("\nAssassin: *ksh* Received order to kill process: %d\n", (int)childPid);
    if (!(status = kill(childPid, SIGKILL))) {
        printf("Assassin: Clean and discreet. My work here is done. *ksh*\n");
    } else {
        printf("Assassin: He got away!\n");
    }
}

void forkyMcFork(int secs)
{
    pid_t pid;
    int status;
    /*Generate information for new program*/
    char* argv[] = {"problem5", "Hello"};
    char* envp[] = {"PANTS=JEANS"};
    char* func = "problem5";

    /* Create child process, child process calls executable "problem5" */
    if ((pid = Fork()) == 0) {
        printf("Child: I am a child! Woohoo!\n");
        if (execve(func, argv, envp) < 0)
            printf("Child: error, %s not found\n", func);
        while(1);
    }
    else {
        /* Parent process sets alarm, then prints a message depending on exit status*/
        childPid = pid;
        alarm(secs);
        printf("Parent: I am the parent!\n");
        waitpid(-1, &status, 0);
        if (!WIFEXITED(status)) {
            printf("Parent: Oh no, what happened to my baby!!!\n");
            exit(0);
        } else {
            printf("Parent: Child came home without any problems.\n");
        }
    }
}

int main(int argc, char const *argv[])
{
    signal(SIGALRM, killhandler);
    forkyMcFork(5);
    return 0;
}

这是它的输出:

$ ./forkfun 
Parent: I am the parent!
Child: I am a child! Woohoo!
Child: error, problem5 not found

Assassin: *ksh* Received order to kill process: 42400
Assassin: Clean and discreet. My work here is done. *ksh*
Parent: Oh no, what happened to my baby!!!
$ 

所以要清楚,这里唯一的代码区别是是否forkyMcFork声明为 take void,在这种情况下它有效,或者 astaking int secs,在这种情况下它不。这是怎么回事?

4

1 回答 1

1

鸭子评论中有一个答案 - 总结一下:

int execve(const char *filename, char *const argv[], char *const envp[]);

argv是传递给新程序的参数字符串数组。 envp 是一个字符串数组,通常采用 key=value 的形式,作为环境传递给新程序。argv 和 envp 都必须以空指针终止。

所以我建议添加 NULL 也用于终止envp

于 2012-10-24T08:15:29.800 回答