2016-12-16 1 views
2

나는 아주 간단한 프로그램을 fork하고 다른 문제를 호출했다. 내가 원하는 것을 수행하는 동안 버그가 발생하고 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

C++을 배우고 있다면이 코드의 절반이 UB 또는 표준 미준수입니다. (헤더 사용법부터 시작합니다.), C를 잊어 버렸습니다. 교사의 요구 사항에 따라 C++의 _features_를 사용하지 않으면 준수하지만 어쩌면 즐거운 시간이 될 것입니다. 대안을보고 그것을 염두에 두는 것을 고려해야한다. – Swift

+0

예 : stdlib.h를 포함하여 UB는 이미 우두머리, cstdlib를 포함하여 그것을했으나. string.h를 포함하는 것도 잘못되었습니다. _global_ scope에서'namespace std'를 사용하면이 스 니펫에는 없지만 가능한 UB가 될 수 있습니다. 로컬 범위에서 사용하거나'std :: cin 사용 '과 같은 필수 이름을 사용할 수 있다는 것을 명심하십시오. 더 이상 STL이 없습니다. STL은 역사적인 이유로 사용할 수있는 별도의 라이브러리입니다. iostream을 사용하고 있다면 이미 STL이 아닌 C++ 템플릿 라이브러리를 사용하고 있습니다. C++ 코드에서 malloc \ free \ realloc을 사용하지 말고 new를 사용하고 delete (및 placement new)를 사용하십시오. – Swift

답변

1

현대 C++ 코드를 작성하는 일반적인 원칙은 무엇이 잘못 되었습니까? 이러한 지독한 C 스타일의 동적 메모리 할당을 사용하는 이유는 어디에도 없습니다. 여기에서 수행 된 모든 작업은 컨테이너를 사용하여 훨씬 더 깔끔하게 수행 할 수 있으며 결과 코드는 최소한 3 배 더 작습니다.

오, 그리고 execv의 매개 변수 배열은 NULL 포인터로 끝나야합니다. 그것은 아니므로 정의되지 않은 동작이 발생합니다. 대부분의 경우 execv 시스템 호출은이 가비지 매개 변수로 인해 실패합니다. 수동 페이지의 내용을 보았을 때 EFAULT 일 가능성이 큽니다.

따라서 execv()은 실제로 하위 프로세스에서 반환됩니다. 표시된 코드가 반환 값을 확인하지 못하기 때문에 하위 프로세스에서 무작위로 자식 프로세스가 execv()에서 돌아 오면 실행을 계속하고 자식 프로세스에서 main()으로 돌아가서 외부 for 루프의 회전 목마를 계속합니다. 따라서 중복 출력이 발생합니다.

+0

STL은 허용되지 않으며 동적 exec를 원하기 때문에 execl을 사용할 수 없으므로 이런 식으로 끝내야합니다. –