2016-12-16 6 views
2

Я сделал очень простую программу, вызывающую forking и вызывающую другую проблему. Пока он делает то, что я хочу, возникает ошибка, а cout происходит в два раза по времени цикла for. Вот код: main.cppНерест детей и exec - неопределенное поведение

`#include <iostream> 
#include <cstdlib> 

#include <stdio.h> 
#include <string.h> 
#include <time.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <sys/ipc.h> 

using namespace std; 

char *Strduplicate(const char *source) { 
    char *dest = (char *) malloc(strlen(source) + 1); // +1 = '\0' 
    if (dest == NULL) 
     return NULL; 
    strcpy(dest, source); 
    return dest; 
} 

string Get_cwd(string word) { 
    char cwd[256]; 
    getcwd(cwd, sizeof(cwd)); 
    strcat(cwd,"/"); 
    strcat(cwd,word.c_str()); 
    string returnVal(cwd); 
    return returnVal; 
} 

void Call_exec(const char *name,int value) { 
    char *exec_array[3]; 
    exec_array[0] = Strduplicate(name); 
    exec_array[1] = (char *)malloc(2); 
    exec_array[1] = (char *)"-m"; 
    asprintf(&(exec_array[2]), "%d", value); 
    for (int i = 0 ; i < 3; i++) 
     cout << exec_array[i] << " "; 
    cout << endl; 
    execv(exec_array[0],exec_array); 
} 

int main(int argc ,char **argv) { 
    srand(time(NULL)); 
    /* Getting arguments */ 
    //........ 
    /* Spawning children */ 
    for (int i = 0 ; i < 3 ; i++) { 
     int value = rand()%100 + 1; 
     pid_t waiterpid = fork(); 
     if (waiterpid < 0) 
      cout << "ERROR FORK" << endl; 
     else if (!waiterpid) { 
      string program_name = Get_cwd("child"); 
      Call_exec(program_name.c_str(),value); 
     } 
    } 
    return EXIT_SUCCESS; 
} 
` 

и другой процесс child.cpp

#include <iostream> 
#include <sys/types.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 

using namespace std; 

int main(int argc ,char **argv) { 
    cout << "Child #" << getpid() << " has started" << endl; 
    int value; 
    /* Getting arguments */ 
    if (argc != 3) { 
     cerr << "ERROR : Wrong arguments" << endl; 
     exit(EXIT_FAILURE); 
    } 
    else { 
     if (strncmp(argv[1],"-m",2) == 0) 
      value = atoi(argv[2]); 
    } 
    cout << "Child has " << value << endl; 
    return EXIT_SUCCESS; 
} 

выход

mypath/child -m 31 
mypath/child -m 23 
mypath/child -m 48 
mypath/child -m 23 
mypath/child -m 48 
[email protected]$ Child #13063 has started 
Child #13062 has started 
Child has 48 
Child has 23 
mypath/child -m 48 
Child #13064 has started 
Child has 48 

Так что я неправильно здесь?

+0

половина этого кода является либо UB, либо стандартным несоответствием (начиная с использования заголовка ..), если вы изучаете C++., Забудьте C. Если это требования преподавателей, чтобы не использовать _features_ на C++, соблюдайте, возможно, хорошее время рассмотреть возможность взглянуть на альтернативы и учесть это. – Swift

+0

, например. в том числе stdlib.h - UB, хотя вы сделали это ПОСЛЕ уже включенного правого заголовка cstdlib. В том числе string.h тоже неправильно. 'using namespace std' в области _global_ может привести к возможным UB, хотя и не в этом фрагменте. Просто имейте в виду, что вы можете использовать использование в локальной области или вытаскивать требуемые имена, например' using std :: cin'. STL больше нет, хорошо, STL - это отдельная библиотека, которая может быть доступна по историческим причинам, если у вас есть iostream, вы уже используете библиотеку шаблонов C++ (а не STL). Не используйте malloc \ free \ realloc в коде C++, используйте новые и удалите (и место размещения новое). – Swift

ответ

1

Здесь неправильно поняты общие принципы написания современного кода на C++. Нет никакой причины использовать эти ужасно выглядящие распределения динамической памяти C-стиля. Все, что сделано здесь, можно сделать гораздо более чистым, используя контейнеры, причем полученный код будет как минимум в три раза меньше.

О, и массив параметров execv должен быть прерван указателем NULL. Это не так, поэтому это приводит к неопределенному поведению. Скорее всего, системный вызов execv терпит неудачу из-за этого параметра мусора - скорее всего, с EFAULT в соответствии с моим прочтением его страницы руководства.

Таким образом, execv() фактически возвращается в дочернем процессе. Так как показанный код не может проверить его возвращаемое значение: дочерний процесс, случайным образом, продолжит выполнение по возврату с execv(), возвращаясь к main() в дочерний процесс и продолжит свой собственный карусель внешнего цикла for , что приводит к дублированию вывода.

+0

STL не разрешен, и поскольку я хочу динамический exec, я не могу использовать execl, поэтому я так и делал это. –