Неожиданное поведение вилки

У меня есть программа, которая работает бесконечно. Для целей тестирования я создал программу-обертку, которая убивает другую по истечении заданного промежутка времени (указанного через аргументы командной строки / терминала). Разветвленная программа требует, чтобы ей были переданы две папки с одним и тем же именем (я не могу это контролировать), поэтому я просто передаю ей один и тот же аргумент дважды, как можно увидеть здесь:

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

1

Решение

Если длина массива является статической, вам может быть лучше

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

Что касается execvp, массив должен начинаться с имени исполняемого файла и заканчиваться NULL,

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

В любом случае, если все, что вам нужно, — это простая оболочка, которая запускает один дочерний элемент с тайм-аутом, тогда ваша программа может быть очень простой и общей, если только вы захотите начать с аргумента тайм-аута:

/*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;
}
2

Другие решения

Массив, переданный в качестве аргументов, должен заканчиваться нулем. Например:

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

Вы можете включить дампы ядра (по окончании убедитесь, что они отключены) ulimit -c unlimited , Запустите его, прежде чем запускать основной процесс. (Я бы не хотел запускать его на развилке, хотя вы, вероятно, можете.)

Когда ваша программа падает, это приводит к дампу ядра, который вы можете проверить с помощью gdb.

Для помощи с основными файлами, вы можете просто погуглить их.

Другое, чем это. Вы можете сделать скрипт, который запускает ваш файл. Вы можете использовать скрипт для записи материала.

1

Ты хочешь:

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

Вам нужен параметр NULL, чтобы отметить конец списка параметров.

1

Учитывая спецификацию:

Форма команды точно:

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

Редко (но не всегда) есть причина для вызова execvp() кроме использования идиомы execvp(argv[0], argv) для массива аргументов в argv,

Обратите внимание, что этот код гарантирует, что поток управления не выйдет из блока операторов, который должен представлять дочерний элемент. Если потом продолжать дочерний процесс, обычно, думая, что это родительский процесс, это приводит к путанице. Всегда убедитесь, что ребенок исполняет или выходит. (Это риторическое преувеличение — да; но за этой идеей тоже стоит большая доля правды.) Кроме того, поскольку это C ++, вам, возможно, придется подумать Как закончить код C ++?. Это усложняет жизнь. Важным моментом является то, что если дочерний процесс не выполняется, он не продолжается, как если бы он был родительским процессом.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector