[英]Unexpected fork behavior
我有一个可以无限期运行的程序。 为了进行测试,我制作了一个包装程序,该程序在指定的时间(通过命令行/终端参数指定)后杀死另一个程序。 被分叉的程序要求将其传递给两个具有相同名称的文件夹(我对此无能为力),因此我只需将两次相同的arg传递给它,如下所示:
pid_t pid = fork();
if(pid == 0)
{
//build the execution string
char* test[2];
test[0] = argv[2];
test[1] = argv[2];
test[2] = NULL;
cout << "test[0] is " << test[0] << endl;
cout << "test[1] is " << test[1] << endl;
cout << "argv[1] is " << argv[1] << endl;
execvp(argv[1],test);
}
问题在于在argv [1]中传递的程序使分段错误不断。 如果我自己通过终端调用,则运行不会有问题。 在两种情况下,我都传递相同的文件夹。 谁能告诉我为什么它对execvp不起作用?
我应该提到一位同事也在他的计算机上运行它,它在第一次运行时就可以正常运行,但是每次之后都会出现故障。
编辑:我添加了一个空项进行测试,但是,这还没有解决问题。
该命令的形式完全是:
<executable> <wrapped prog> <folder> <duration>
在相对路径中:
Intel/debug/Tester.exe <program> test 10
作为参数传递的数组应为空终止。 例如:
char *test[3]={0};
...
如果数组的长度是静态的,那么使用以下方法可能会更好
execlp
execlp(argv[1], argv[1], argv[2], argv[2], (char*)0);
至于execvp
,数组应以可执行文件的名称开头,以NULL
结尾。
execvp
char* args[] = { argv[1], argv[2], argv[2], NULL };
execvp(argv[1], args);
无论如何,如果您想要的只是一个简单的包装程序,该包装程序运行一个带有超时的子进程,那么只要您愿意从timeout参数开始,您的程序就可以非常简单和通用:
/*runWithTimeout.c
compile with: make runWithTimeout
run with: ./runWithTimeout seconds program arguments...
*/
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
int main(int argc, char** argv)
{
assert(argc >= 1+2);
int pid, status = 1;
if((pid = fork()) == 0) {
alarm(atoi(argv[1]));
execvp(argv[2], argv + 2);
/*^the child ends here if execvp succeeds,
otherwise fall-through and return the default error status of 1
(once in child (which has no one to wait on) and
then in the parent (which gets the status from the child))*/
perror("Couldn't exec");
}else if(pid < 0){ perror("Couldn't fork"); };
wait(&status);
return status;
}
您可以打开核心转储(确保完成ulimit -c unlimited
其关闭) ulimit -c unlimited
。 在运行主进程之前先运行它。 (尽管您可以,但我会很乐意将其运行在fork中。)
当程序崩溃时,将生成一个核心转储,您可以使用gdb进行检查。
要获取核心文件的帮助,您可以将其谷歌搜索。
除此之外。 您可以创建一个脚本来启动文件。 您可以使用脚本来记录内容。
你要:
char* test[3];
test[0] = argv[2];
test[1] = argv[2];
test[2] = NULL;
您需要一个NULL参数来标记参数列表的末尾。
给定规格:
该命令的形式完全是:
<executable> <wrapped prog> <folder> <duration>
在相对路径中:
Intel/debug/Tester.exe <program> test 10
并且:
分叉的程序要求将其传递给两个具有相同名称的文件夹…
然后,假设您已检查包装器是否传递了4个参数,则所需的代码是:
pid_t pid = fork();
if (pid == 0)
{
//build the execution string
char *test[4]; // Note the size!
test[0] = argv[1]; // Program name: argv[0] in exec'd process
test[1] = argv[2]; // Directory name: argv[1] …
test[2] = argv[2]; // Directory name: argv[2] …
test[3] = NULL; // Null terminator
cout << "test[0] is " << test[0] << endl;
cout << "test[1] is " << test[1] << endl;
cout << "test[2] is " << test[2] << endl;
execvp(test[0], test);
cerr << "Failed to exec '" << test[0] << "': " << strerror(errno) << endl;
exit(1); // Or throw an exception, or …
}
除了对argv
的参数数组使用惯用法execvp(argv[0], argv)
,很少(但并非从来没有)理由调用execvp()
。
请注意,此代码可确保控制流不会从应该代表子代的语句块中逸出。 随后让子进程继续进行,通常实际上是认为它是父进程,这会导致混乱。 始终确保孩子执行或退出。 (这是夸夸其谈的说法-是的;但是这个想法背后也有很多道理。)而且,由于这是C ++,因此您可能需要考虑如何结束C ++代码? 。 这使生活变得复杂。 至关重要的是,如果子进程无法执行,它将不会像父进程一样继续执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.