2012-10-24 44 views
1

我正在玩弄信号,叉子和execve,我写了一个玩具程序,它使用fork()来创建一个调用另一个玩具程序的子进程。然后,父母设置一个警报,在一定的秒数后终止该功能。C:使用参数声明函数会改变其行为...?

#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),应当由被称为外部程序找不到子项目中的语句。警报按预期运行,因此在几秒钟后,子进程将被削减。

这里的非工作代码:

#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被声明为接受void ,在这种情况下它可以工作,或者采取int secs,在这种情况下它不会。这是怎么回事?

+0

当你从'execve'得到错误时,打印'errno'的值,或者更好的使用['strerror'](http://linux.die.net/man/3/strerror)来获得错误代码的可打印文本。 –

+2

也请显示_fails_程序,而不是成功的程序。 –

+4

在ForkyMcFork()的argv和envp变量的末尾添加一个空参数。你可能只是幸运的版本作品。 – Duck

回答

1

有鸭评论答案 - 所以只是总结:

INT的execve(为const char *文件名,char * const的ARGV [], char * const的envp []);

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

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