简体   繁体   English

意外的分叉行为

[英]Unexpected fork behavior

I have a program that runs indefinitely. 我有一个可以无限期运行的程序。 For testing purposes I have made a wrapper program that kills the other after a specified amount of time (specified via command line/terminal args). 为了进行测试,我制作了一个包装程序,该程序在指定的时间(通过命令行/终端参数指定)后杀死另一个程序。 The program being forked requires that it is passed two folders with the same name (I have no control over this), so I simply pass it the same arg twice as can be seen here: 被分叉的程序要求将其传递给两个具有相同名称的文件夹(我对此无能为力),因此我只需将两次相同的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);
}

The problem is that the program being passed in argv[1] keeps segmentation faulting. 问题在于在argv [1]中传递的程序使分段错误不断。 If I call the by itself via the terminal it runs with no problems. 如果我自己通过终端调用,则运行不会有问题。 I am passing the same folder in both cases. 在两种情况下,我都传递相同的文件夹。 Can anyone tell me why it isn't working for execvp? 谁能告诉我为什么它对execvp不起作用?

I should mention a co-worker ran it on his computer as well, and it will stand up fine the first time, but each time after that, it will seg fault. 我应该提到一位同事也在他的计算机上运行它,它在第一次运行时就可以正常运行,但是每次之后都会出现故障。

edit: I have added a null term to test, however, this has not fixed the issue. 编辑:我添加了一个空项进行测试,但是,这还没有解决问题。

The command's form is exactly: 该命令的形式完全是:

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

In relative paths it's: 在相对路径中:

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

Array passed as arguments should be null-terminated. 作为参数传递的数组应为空终止。 For example: 例如:

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

If the length of the array is static, you might be better off with 如果数组的长度是静态的,那么使用以下方法可能会更好

execlp

execlp(argv[1], argv[1], argv[2], argv[2], (char*)0);

As for execvp , the array should start with the name of the executable and end with NULL . 至于execvp ,数组应以可执行文件的名称开头,以NULL结尾。

execvp

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

runWithTimeout runWithTimeout

In any case, if all you want is a simple wrapper that runs a single child with a timeout, then your program could be very simple and general if only you'd be willing to start with the timeout argument: 无论如何,如果您想要的只是一个简单的包装程序,该包装程序运行一个带有超时的子进程,那么只要您愿意从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;
}

You can turn on core dumps ( make sure to shut them off when done ) ulimit -c unlimited . 您可以打开核心转储(确保完成ulimit -c unlimited其关闭) ulimit -c unlimited Run it before you run your main process. 在运行主进程之前先运行它。 ( I would be leary of running it in the fork though you probably can. ) (尽管您可以,但我会很乐意将其运行在fork中。)

When your program crashes this will produce a core dump which you can examine with gdb. 当程序崩溃时,将生成一个核心转储,您可以使用gdb进行检查。

For help with core files, you can just google them. 要获取核心文件的帮助,您可以将其谷歌搜索。

Other then that. 除此之外。 You can make a script which launches your file. 您可以创建一个脚本来启动文件。 You can use the script to log stuff. 您可以使用脚本来记录内容。

You want: 你要:

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

You need a NULL parameter to mark the end of the parameter list. 您需要一个NULL参数来标记参数列表的末尾。

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: 然后,假设您已检查包装器是否传递了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 …
}

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 . 除了对argv的参数数组使用惯用法execvp(argv[0], argv) ,很少(但并非从来没有)理由调用execvp()

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? (这是夸夸其谈的说法-是的;但是这个想法背后也有很多道理。)而且,由于这是C ++,因此您可能需要考虑如何结束C ++代码? . 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. 至关重要的是,如果子进程无法执行,它将不会像父进程一样继续执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM