我正在玩信号,分叉和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()
的参数,那么它就像我期望的那样工作:子进程启动{ {1}},要求用户提供一些输入,然后在3秒后problem5
运行,找到子进程并将其杀死:
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
,在这种情况下它是有效的,还是采用void
,在这种情况下它不会“T。发生了什么事?
答案 0 :(得分:1)
Duck评论中有一个答案 - 所以只是总结一下:
int execve(const char * filename,char * const argv [], char * const envp []);
argv 是传递给新程序的参数字符串数组。 envp 是一个 字符串数组,通常为key = value形式,传递方式为 环境对新计划的影响。 argv和envp都必须以a终止 空指针。
因此我建议添加NULL以终止 envp 。