意外的fork行为

时间:2015-07-27 14:01:21

标签: c++ linux fork execvp

我有一个无限期运行的程序。出于测试目的,我制作了一个包装器程序,在指定的时间后(通过命令行/终端args指定)杀死另一个程序。分叉的程序要求它传递两个具有相同名称的文件夹(我无法控制它),所以我只是将它传递给相同的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

5 个答案:

答案 0 :(得分:2)

作为参数传递的数组应该以null结尾。例如:

char *test[3]={0};
...

答案 1 :(得分:2)

如果数组的长度是静态的,那么使用

可能会更好

$elements = 'asdadasdsa|asdsa'; oci_bind_by_name($stmt, ':elements', $elements);

execlp

对于execlp(argv[1], argv[1], argv[2], argv[2], (char*)0); ,数组应以可执行文件的名称开头,以execvp结尾。

NULL

execvp

runWithTimeout

在任何情况下,如果您想要的只是一个运行单个子超时的简单包装器,那么只要您愿意以超时参数开始,您的程序就会非常简单和通用:

char* args[] = { argv[1], argv[2], argv[2], NULL };
execvp(argv[1], args);

答案 2 :(得分:1)

您可以启用核心转储(确保在完成后关闭它们)ulimit -c unlimited。在运行主进程之前运行它。 (尽管你可能可以,但我会在叉子里运行它。)

当你的程序崩溃时,这会产生一个你可以用gdb检查的核心转储。

有关核心文件的帮助,您只需谷歌搜索。

除此之外。您可以创建一个启动文件的脚本。您可以使用该脚本记录内容。

答案 3 :(得分:1)

你想:

char* test[3];
test[0] = argv[2];
test[1] = argv[2];
test[2] = NULL;

您需要一个NULL参数来标记参数列表的结尾。

答案 4 :(得分:1)

Given the specification:

The command's form is exactly:

<executable> <wrapped prog> <folder> <duration>

In relative paths it's:

Intel/debug/Tester.exe <program> test 10

and also:

The program being forked requires that it is passed two folders with the same name…

then, assuming you've checked that the wrapper is passed 4 arguments, the code you need is:

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 …
}

There is seldom (but not never) a reason to invoke execvp() other than using the idiom execvp(argv[0], argv) for the array of arguments in argv.

Note that this code ensures that the control flow doesn't escape from the statement block that is supposed to represent the child. Having the child process continue afterwards, usually in effect thinking it is a parent process, leads to confusion. Always make sure the child execs or exits. (That's a rhetorical over-statement — yes; but there's a large chunk of truth behind the idea too.) Also, since this is C++, you may need to consider How to end C++ code?. That complicates life. The crucial thing is that if the child process fails to exec, it does not continue as if it was a parent process.