2012-10-24 41 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