C++ 意外的分叉行为

C++ 意外的分叉行为,c++,linux,fork,execvp,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]; te

我有一个无限期运行的程序。出于测试目的,我制作了一个包装程序,在指定的时间(通过命令行/终端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);
}
pid_t pid=fork();
如果(pid==0)
{
//构建执行字符串
字符*测试[2];
测试[0]=argv[2];
测试[1]=argv[2];
测试[2]=NULL;

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

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

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

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

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

execlp
对于
execvp
,数组应该以可执行文件的名称开头,以
NULL
结尾

execvp
runWithTimeout 在任何情况下,如果您只需要一个简单的包装器来运行一个带超时的子级,那么您的程序可以非常简单和通用,只要您愿意从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;
}
/*runWithTimeout.c
编译方式:make runWithTimeout
使用以下参数运行:./runWithTimeout seconds程序参数。。。
*/
#包括
#包括
#包括
int main(int argc,字符**argv)
{
断言(argc>=1+2);
int pid,状态=1;
如果((pid=fork())==0){
警报(atoi(argv[1]);
execvp(argv[2],argv+2);
/*^如果execvp成功,则子项在此结束,
否则将失败并返回默认错误状态1
(一次分娩(无需等待)和
然后在父级中(从子级获取状态))*/
佩罗(“无法执行”);
}else如果(pid<0){perror(“cannotfork”);};
等待(&状态);
返回状态;
}

如果数组的长度是静态的,您最好使用

execlp
对于
execvp
,数组应该以可执行文件的名称开头,以
NULL
结尾

execvp
runWithTimeout 在任何情况下,如果您只需要一个简单的包装器来运行一个带超时的子级,那么您的程序可以非常简单和通用,只要您愿意从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;
}
/*runWithTimeout.c
编译方式:make runWithTimeout
使用以下参数运行:./runWithTimeout seconds程序参数。。。
*/
#包括
#包括
#包括
int main(int argc,字符**argv)
{
断言(argc>=1+2);
int pid,状态=1;
如果((pid=fork())==0){
警报(atoi(argv[1]);
execvp(argv[2],argv+2);
/*^如果execvp成功,则子项在此结束,
否则将失败并返回默认错误状态1
(一次分娩(无需等待)和
然后在父级中(从子级获取状态))*/
佩罗(“无法执行”);
}else如果(pid<0){perror(“cannotfork”);};
等待(&状态);
返回状态;
}

您可以打开核心转储(完成后请确保将其关闭)
ulimit-c unlimited
。在运行主进程之前运行它。(虽然您可能可以,但我很了解如何在fork中运行它。)

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

要获得有关核心文件的帮助,您可以用谷歌搜索它们


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

您可以打开核心转储(完成后确保关闭它们)
ulimit-c unlimited
。在运行主进程之前运行它。(虽然您可能可以,但我很了解如何在fork中运行它。)

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

要获得有关核心文件的帮助,您可以用谷歌搜索它们

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

您需要:

char* test[3];
test[0] = argv[2];
test[1] = argv[2];
test[2] = NULL;
您需要一个空参数来标记参数列表的结尾。

您需要:

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

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

给定规范:

该命令的形式正是:

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

在相对路径中,它是:

Intel/debug/Tester.exe <program> test 10
Intel/debug/Tester.exe <program> test 10
英特尔/debug/Tester.exe测试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 …
}
pid_t pid=fork();
如果(pid==0)
{
//构建执行字符串
char*test[4];//注意大小!
test[0]=argv[1];//执行进程中的程序名:argv[0]
test[1]=argv[2];//目录名:argv[1]…
test[2]=argv[2];//目录名:argv[2]…
test[3]=NULL;//NULL终止符

cout给定规格:

该命令的形式正是:

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

在相对路径中,它是:

Intel/debug/Tester.exe <program> test 10
Intel/debug/Tester.exe <program> test 10
英特尔/debug/Tester.exe测试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 …
}
pid_t pid=fork();
如果(pid==0)
{
//构建执行字符串
char*test[4];//注意大小!
test[0]=argv[1];//执行进程中的程序名:argv[0]
test[1]=argv[2];//目录名:argv[1]…
test[2]=argv[2];//目录名:argv[2]…
test[3]=NULL;//NULL终止符

cout您要让它执行的确切命令行是什么?test
数组应该以可执行文件的名称开头,以NULL结尾。它应该以filename开头,但这只是出于约定的目的。使用-as
strace-f
了解发生了什么,您至少应该有一个
exit()
调用,最好在
execvp()之后打印一条错误消息。
打开