티스토리 뷰
☞ system, execv, execl, execve, execle, execvp, execlp
<stdlib.h>
<unistd.h>
int system(const char *command);
int execv(const char *filename, char *const argv[]);
int execl(const char *filename, const char *arg0, ...);
int execve(const char *filename, char *const argv[], char *const env[]);
int execle(const char *filename, const char *arg0, ..., char *const env[]);
int execvp(const char *filename, char *const argv[]);
int execlp(const char *filename, const char *arg0, ...);
실행중인 프로그램에서 다른 프로그램을 실행시키는 방법들 입니다. 가장 간단한 방법은 system() 함수를 사용하는 것으로 자세한 컨트롤은 할 수 없지만 쉘 또는 콘솔에서 명령을 수행하는 것처럼 명령행 문자열을 인수로 넘기면 쉘을 통해서 지정한 명령을 수행합니다. command를 통해서 수행을 지시한 명령이 끝날때까지 system() 함수는 리턴하지 않습니다.
☞ 예제1
void csql_invoke_system (const char *command) { bool error_found = false; /* TRUE if error found */ if (system (command) == 127) { error_found = true; csql_Error_code = CSQL_ERR_OS_ERROR; } if (error_found) { nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN); } }
위의 예제는 큐브리드 DBMS의 코드 일부로 사용자가 프로그램 수행중에 시스템 명령을 수행하고 싶을때 system()함수를 통해서 사용자가 입력한 명령을 수행시켜주는 과정입니다. 실행중인 프로세스에서 다른 프로그램을 실행시키는 과정을 살펴보면 그 시작은 fork()를 통해서 자식 프로세스를 생성하는 것으로 시작합니다. fork()는 기존 프로세스와 동일한 복사본을 새롭게 만들고 새로운 프로세스 ID를 부여합니다. 이 시점부터 부모 프로세스와 자식 프로세스는 각각 독립적으로 동시 수행됩니다. 자식 프로세스가 종료되면 부모 프로세스로 시그널을 전송하는 것으로 그 생애를 마감합니다. 부모 프로세스가 자식 프로세스의 실행이 종료 될 때 까지 실행을 잠시 멈추고 싶다면 wait() 또는 waitpid()를 호출하면 됩니다. system() 함수는 이런 과정을 단순화 시켜 준 것입니다.
☞ 예제2
static pgpid_t start_postmaster(void) { char cmd[MAXPGPATH]; #ifndef WIN32 pgpid_t pm_pid; /* Flush stdio channels just before fork, to avoid double-output problems */ fflush(stdout); fflush(stderr); pm_pid = fork(); if (pm_pid < 0) { /* fork failed */ write_stderr(_("%s: could not start server: %s\n"), progname, strerror(errno)); exit(1); } if (pm_pid > 0) { /* fork succeeded, in parent */ return pm_pid; } /* fork succeeded, in child */ if (log_file != NULL) snprintf(cmd, MAXPGPATH, "exec \"%s\" %s%s < \"%s\" >> \"%s\" 2>&1", exec_path, pgdata_opt, post_opts, DEVNULL, log_file); else snprintf(cmd, MAXPGPATH, "exec \"%s\" %s%s < \"%s\" 2>&1", exec_path, pgdata_opt, post_opts, DEVNULL); (void) execl("/bin/sh", "/bin/sh", "-c", cmd, (char *) NULL); /* exec failed */ write_stderr(_("%s: could not start server: %s\n"), progname, strerror(errno)); exit(1); return 0; /* keep dumb compilers quiet */ #else /* WIN32 */ PROCESS_INFORMATION pi; if (log_file != NULL) snprintf(cmd, MAXPGPATH, "CMD /C \"\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1\"", exec_path, pgdata_opt, post_opts, DEVNULL, log_file); else snprintf(cmd, MAXPGPATH, "CMD /C \"\"%s\" %s%s < \"%s\" 2>&1\"", exec_path, pgdata_opt, post_opts, DEVNULL); if (!CreateRestrictedProcess(cmd, &pi, false)) { write_stderr(_("%s: could not start server: error code %lu\n"), progname, (unsigned long) GetLastError()); exit(1); } /* Don't close command process handle here; caller must do so */ postmasterProcess = pi.hProcess; CloseHandle(pi.hThread); return pi.dwProcessId; /* Shell's PID, not postmaster's! */ #endif /* WIN32 */ }
위의 예제는 PostgreSQL DBMS 코드의 일부로 fork()로 자식 프로세스를 생성하는 과정을 참조해 볼 수 있습니다.
fork() 함수를 호출한 다음에 부모 프로세스는 0보다 큰 값을 리턴 받으므로 함수를 빠져 나가고
실제 작업을 수행할 자식 프로세스에서는 execl()을 통해서 외부 명령을 수행하고 있습니다.
주의할 점은 윈도우 운영체제에서는 exec*()함수들 대신에 별도의 API를 사용하고 있으므로 필요에 따라 적절하게 활용할 필요가 있습니다.
exec*() 함수들은 프로그램 아규먼트를 어떻게 전달할 것인지만 다를뿐 fork()로 생성된 자식 프로세스 이미지로 filename으로 지정한 파일을 실행시키는 것은 동일합니다.
'C | C++' 카테고리의 다른 글
벡터 클래스(std::vector) 정리 (0) | 2024.01.22 |
---|---|
프로세스 생성과 관리 (0) | 2018.08.04 |
프로그램 종료 (0) | 2018.08.04 |
환경 변수 다루기 (0) | 2018.08.04 |
프로그램 아규먼트와 옵션 처리 (0) | 2018.08.04 |