728x90
반응형
SMALL
1. Fork란?
Fork는 Unix/Linux 시스템에서 새로운 프로세스를 생성하는 시스템 콜입니다.
현재 실행 중인 프로세스(부모 프로세스)를 복제하여 새로운 프로세스(자식 프로세스)를 만듭니다.
2. Fork의 특징
- 프로세스 복제: 부모 프로세스의 메모리, 파일 디스크립터, 레지스터 등을 복사
- 독립적 실행: 자식 프로세스는 부모와 독립적으로 실행
- 반환값 차이:
- 부모 프로세스: 자식의 PID(Process ID) 반환
- 자식 프로세스: 0 반환
- 실패 시: -1 반환
3. 기본 예제
예제 1: 간단한 Fork
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
pid_t pid;
printf("Fork 실행 전 - PID: %d\n", getpid());
pid = fork();
if (pid < 0) {
// Fork 실패
fprintf(stderr, "Fork 실패\n");
return 1;
}
else if (pid == 0) {
// 자식 프로세스
printf("자식 프로세스 - PID: %d, 부모 PID: %d\n",
getpid(), getppid());
}
else {
// 부모 프로세스
printf("부모 프로세스 - PID: %d, 자식 PID: %d\n",
getpid(), pid);
}
printf("프로세스 %d 종료\n", getpid());
return 0;
}
출력 예시:
Fork 실행 전 - PID: 1234
부모 프로세스 - PID: 1234, 자식 PID: 1235
프로세스 1234 종료
자식 프로세스 - PID: 1235, 부모 PID: 1234
프로세스 1235 종료
출력 순서는 실행할 때마다 바뀔 수 있습니다.
예제 2: 부모-자식 프로세스의 변수 독립성
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int x = 10;
pid_t pid = fork();
if (pid == 0) {
// 자식 프로세스
x = 20;
printf("자식: x = %d\n", x);
}
else {
// 부모 프로세스
wait(NULL); // 자식이 끝날 때까지 대기
printf("부모: x = %d\n", x);
}
return 0;
}
출력:
자식: x = 20
부모: x = 10
예제 3: 다중 Fork
#include <stdio.h>
#include <unistd.h>
int main() {
printf("시작\n");
fork(); // 첫 번째 fork - 2개 프로세스
fork(); // 두 번째 fork - 4개 프로세스
printf("PID: %d\n", getpid());
return 0;
}
출력 (총 4개 프로세스):
시작
PID: 1234
PID: 1235
PID: 1236
PID: 1237
예제 4: exec()와 함께 사용
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
// 자식 프로세스: 다른 프로그램 실행
printf("자식: ls 명령어 실행\n");
execlp("/bin/ls", "ls", "-l", NULL);
// exec이 성공하면 이 코드는 실행되지 않음
perror("exec 실패");
}
else {
// 부모 프로세스
printf("부모: 자식 프로세스 대기 중...\n");
wait(NULL);
printf("부모: 자식 프로세스 종료됨\n");
}
return 0;
}
출력
부모: 자식 프로세스 대기 중...
자식: ls 명령어 실행
total 24
-rwxr-xr-x 1 user user 16784 Oct 24 10:30 a.out
-rw-r--r-- 1 user user 445 Oct 24 10:29 fork_exec.c
-rw-r--r-- 1 user user 123 Oct 24 09:15 test.txt
부모: 자식 프로세스 종료됨
또는 (자식이 먼저 실행되면):
자식: ls 명령어 실행
total 24
-rwxr-xr-x 1 user user 16784 Oct 24 10:30 a.out
-rw-r--r-- 1 user user 445 Oct 24 10:29 fork_exec.c
-rw-r--r-- 1 user user 123 Oct 24 09:15 test.txt
부모: 자식 프로세스 대기 중...
부모: 자식 프로세스 종료됨
예제 5: 여러 자식 프로세스 생성
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int n = 3;
for (int i = 0; i < n; i++) {
pid_t pid = fork();
if (pid == 0) {
// 자식 프로세스
printf("자식 %d - PID: %d\n", i, getpid());
sleep(1);
return 0; // 자식은 여기서 종료
}
}
// 부모 프로세스만 여기 도달
printf("부모 프로세스: 모든 자식 대기 중\n");
// 모든 자식 프로세스 종료 대기
for (int i = 0; i < n; i++) {
wait(NULL);
}
printf("부모 프로세스: 모든 자식 종료됨\n");
return 0;
}
가능한 출력 결과들
출력 예시 1: 순차적으로 출력
자식 0 - PID: 1235
자식 1 - PID: 1236
자식 2 - PID: 1237
부모 프로세스: 모든 자식 대기 중
부모 프로세스: 모든 자식 종료됨
출력 예시 2: 역순으로 출력
자식 2 - PID: 1237
자식 1 - PID: 1236
자식 0 - PID: 1235
부모 프로세스: 모든 자식 대기 중
부모 프로세스: 모든 자식 종료됨
출력 예시 3: 섞여서 출력
자식 0 - PID: 1235
자식 2 - PID: 1237
자식 1 - PID: 1236
부모 프로세스: 모든 자식 대기 중
부모 프로세스: 모든 자식 종료됨
출력 예시 4: 부모가 먼저 출력
부모 프로세스: 모든 자식 대기 중
자식 0 - PID: 1235
자식 1 - PID: 1236
자식 2 - PID: 1237
부모 프로세스: 모든 자식 종료됨
출력 예시 5: 완전히 섞임
자식 0 - PID: 1235
부모 프로세스: 모든 자식 대기 중
자식 1 - PID: 1236
자식 2 - PID: 1237
부모 프로세스: 모든 자식 종료됨
4. Fork의 주요 용도
- 병렬 처리: 여러 작업을 동시에 수행
- 서버 프로그래밍: 클라이언트 요청마다 새 프로세스 생성
- 프로그램 실행: fork() + exec()로 새 프로그램 실행
- 데몬 프로세스: 백그라운드 서비스 생성
5. 주의사항
- 좀비 프로세스: 자식이 종료되었지만 부모가 wait()하지 않으면 발생
- 고아 프로세스: 부모가 먼저 종료되면 자식은 init 프로세스에 입양됨
- 리소스 소비: Fork는 메모리를 복사하므로 비용이 큼 (COW 기법으로 최적화)
728x90
반응형
LIST