1

私はシグナル、フォーク、および 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、 が taking として宣言されてvoidいる場合は動作するか、 take として宣言されて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を終了するためにもNULLを追加することをお勧めします。

于 2012-10-24T08:15:29.800 に答える