fork()와 wait() 시스템 콜을 이용하여 부모와 자식 프로세스를 생성하고 동작시킵니다.fork(): 새로운 자식 프로세스를 생성하며, 부모와 자식 프로세스는 동시에 실행됩니다.wait(): 부모 프로세스가 자식 프로세스의 종료를 기다립니다.작동 방식:
fork()는 현재 프로세스를 복사하여 새로운 자식 프로세스를 생성합니다.차이점:
fork()는 반환 값으로 부모와 자식 간의 차이를 만듭니다:결과:
역할:
wait()를 호출하여 자식 프로세스의 종료를 기다립니다.장점:
wait() 시스템 콜은 부모 프로세스가 자식 프로세스의 종료를 대기하게 만듭니다.wait()는 리턴하며 자식의 PID를 반환합니다.#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { // 자식 프로세스
printf("hello, I am child (pid:%d)\n", (int) getpid());
} else { // 부모 프로세스
int wc = wait(NULL); // 자식 프로세스의 종료 대기
printf("hello, I am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int) getpid());
}
return 0;
}
prompt> ./p2
hello world (pid:29266)
hello, I am child (pid:29267)
hello, I am parent of 29267 (wc:29267) (pid:29266)
부모와 자식 프로세스의 생성:
fork() 시스템 콜로 부모와 자식 프로세스가 생성됩니다.rc에 자식의 PID를 반환받고, 자식은 rc == 0을 반환받습니다.wait() 호출로 인한 부모의 대기:
wait()를 호출합니다.출력 순서 결정:
wait()가 리턴한 후 출력 작업을 수행하므로 항상 자식 출력이 부모 출력보다 먼저 나타납니다.wait()의 반환 값:
wait()가 부모 프로세스의 실행을 자식 프로세스가 종료될 때까지 중단시키므로, 자식이 항상 먼저 실행을 완료하고 출력을 수행합니다.hello world (부모와 자식 공통 출력)hello, I am child (자식 출력)hello, I am parent (부모 출력)exec() 시스템 콜은 현재 실행 중인 프로세스를 대체하여 새로운 프로그램을 실행합니다.#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char *argv[]) {
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) { // fork 실패
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { // 자식 프로세스
printf("hello, I am child (pid:%d)\n", (int) getpid());
// 실행할 프로그램과 인자 설정
char *myargs[3];
myargs[0] = strdup("wc"); // 실행할 프로그램: wc
myargs[1] = strdup("p3.c"); // 인자: 파일 이름 p3.c
myargs[2] = NULL; // 인자의 끝 표시
// execvp()로 현재 프로세스를 대체
execvp(myargs[0], myargs);
// execvp()가 성공하면 이 부분은 실행되지 않음
printf("this shouldn't print out\n");
} else { // 부모 프로세스
int wc = wait(NULL); // 자식 프로세스의 종료 대기
printf("hello, I am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int) getpid());
}
return 0;
}
prompt> ./p3
hello world (pid:29383)
hello, I am child (pid:29384)
29 107 1030 p3.c
hello, I am parent of 29384 (wc:29384) (pid:29383)
fork()로 자식 프로세스 생성:
fork()를 호출하여 자식 프로세스를 생성합니다.자식 프로세스에서 exec() 호출:
execvp()를 호출하여 현재 프로세스를 wc 프로그램으로 대체합니다.wc는 파일의 행 수, 단어 수, 바이트 수를 출력하는 프로그램입니다.부모 프로세스에서 wait() 호출:
wait()를 호출하여 자식 프로세스가 종료될 때까지 대기합니다.현재 프로세스를 대체:
exec() 호출 시 현재 프로세스의 메모리 공간은 새 프로그램으로 완전히 덮어씌워집니다.프로세스 ID 유지:
exec()를 호출해도 프로세스 ID(PID)는 유지됩니다.리턴하지 않음:
exec()가 성공하면 호출한 함수로 다시 돌아오지 않습니다."this shouldn't print out"라는 메시지는 절대 출력되지 않습니다.execvp()를 호출하여 wc 프로그램으로 대체되며, 바로 출력 작업을 수행합니다.wait()를 호출하여 자식 프로세스가 종료될 때까지 대기한 후 출력을 완료합니다.hello world (부모와 자식 공통)wc 실행 결과 출력.fork()와 exec()를 분리하여 프로세스를 생성하고 실행하도록 설계되었습니다.쉘의 역할:
fork()로 자식 프로세스를 생성한 뒤, exec() 호출 전에 추가 작업(환경 설정, 입출력 재지정 등)을 수행할 수 있습니다.환경 설정의 유연성:
fork()와 exec()를 분리하면 쉘이 다음과 같은 작업을 쉽게 수행할 수 있습니다:wc p3.c > newfile.txt에서 > newfile.txt를 처리.입출력 재지정 예제:
p4.c에서 자식 프로세스는 표준 출력을 닫고 새 파일에 연결합니다.#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
int rc = fork();
if (rc < 0) { // fork 실패
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { // 자식 프로세스
close(STDOUT_FILENO); // 표준 출력 닫기
open("./p4.output", O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU); // 새 파일로 출력 연결
// 실행할 프로그램과 인자 설정
char *myargs[3];
myargs[0] = strdup("wc"); // 실행할 프로그램: wc
myargs[1] = strdup("p4.c"); // 인자: 파일 이름 p4.c
myargs[2] = NULL; // 인자의 끝 표시
execvp(myargs[0], myargs); // execvp()로 현재 프로세스를 wc로 대체
} else { // 부모 프로세스
int wc = wait(NULL); // 자식 프로세스 종료 대기
}
return 0;
}
prompt> ./p4
prompt> cat p4.output
32 109 846 p4.c
fork()로 자식 프로세스 생성:
자식 프로세스에서 입출력 재지정:
close(STDOUT_FILENO)로 표준 출력을 닫고, open()을 통해 새 파일을 열어 연결합니다.execvp()로 프로그램 실행:
execvp()는 wc 프로그램으로 자식 프로세스를 대체합니다.부모 프로세스 대기:
wait()로 자식 프로세스 종료를 대기하며, 이후 다음 작업을 수행합니다.exec() 호출 전에 자식 프로세스에서 다양한 작업(환경 설정, 우선순위 변경, 입출력 재지정 등)을 수행할 수 있습니다.fork()와 exec() 조합은 단순하고 효율적이면서도 다양한 작업을 지원합니다.kill():
kill -9 <PID>: 특정 PID의 프로세스를 강제 종료(SIGKILL).kill -STOP <PID>: 특정 프로세스를 일시 정지(SIGSTOP).kill -CONT <PID>: 정지된 프로세스를 재개(SIGCONT).시그널(signal):
ps:
ps -e: 모든 프로세스를 표시.ps -f: 프로세스의 세부 정보를 포맷팅하여 표시.ps aux: 실행 중인 모든 프로세스의 상세 정보를 표시.top:
파일 기반 모니터링:
/proc 파일 시스템:/proc/<PID>: 특정 프로세스의 상태와 자원 사용 정보./proc/stat: 시스템의 CPU 및 메모리 사용 상태.MenuMeter (Macintosh):
Linux의 uptime:
vmstat:
프로세스 관리:
ps, top, /proc를 통해 프로세스 상태와 자원 사용량을 모니터링.kill과 시그널로 특정 프로세스를 제어하거나 중단.시스템 부하 분석:
top과 vmstat로 CPU 및 메모리 사용량을 점검.운영체제 학습 및 디버깅: