프로세스 API는 운영체제(OS)가 애플리케이션에 제공하는 인터페이스로, 사용자 프로그램이 운영체제의 다양한 기능을 사용할 수 있도록 해주는 시스템 호출이다. 이는 프로세스의 생성, 종료, 정지, 제개와 같은 기본적인 관리 작업뿐만 아니라, 프로세스 상태 정보 제공, 메모리 할당, 파일 접근 등 가상 머신 관련 기능을 요청하는데 필수적이다. 또한, 프로세스 API는 프로세스뿐만 아니라 모듈(실행 파일 또는 DLL)과 드라이버에 대한 정보 조회 및 메모리 사용량 데이터 수집과 같은 고급 기능도 지원한다.
이 중 fork(), wait(), exec()는 프로세스의 생성, 실행, 대기 및 종료를 다루는 데 필수적인 API 이다.
fork() 시스템 콜
fork() 시스템 콜은 현재 실행 중인 프로세스(부모 프로세스)와 쪽 같은 복사본인 새로운 프로세스(자식 프로세스)를 생성하는 기능을 한다.
용어 설명:
- 프로세스: 실행 중인 프로그램의 인스턴스로, 자체적인 메모리 공간과 시스템 자원을 가짐.
- 시스템 콜: 운영 체제에게 특정 작업을 요청하기 위해 프로그램이 사용하는 인터페이스.
- PID (프로세스 식별자): 각 프로세스를 고유하게 식별하기 위해 운영 체제가 할당하는 번호.
fork()로 생성된 자식 프로세스는 부모 프로세스의 메모리 공간을 복사하여 가지게 된다. 여기에는 다음과 같은 영역이 포함된다:
- 데이터: 전역 변수와 정적 변수가 저장되는 영역
- 코드: 프로그램의 실행 가능한 기계어 코드가 저장되는 영역
- 힙: 동적으로 할당되는 메모리 영역
- 스택: 함수 호출과 지역 변수 등을 관리하는 영역
하지만 부모 프로세스와 자식 프로세스는 서로 다른 PID를 가지며, 독립적으로 실행된다. 이를 통해 동시에 여러 작업을 수행할 수 있게 되어 시스템의 효율성과 응답성을 높일 수 있다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]){
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) { // fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { // child (new process)
printf("hello, I am child (pid:%d)\n", (int) getpid());
} else { // parent goes down this path (main)
printf("hello, I am parent of %d (pid:%d)\n", rc, (int) getpid());
}
return 0;
}
wait() 시스템 콜
wait() 시스템 콜은 부모 프로세스가 자식 프로세스의 종료를 대기하는 기능을 한다. 자식 프로세스가 종료될 때까지 부모 프로세스의 실행을 잠시 멈춘다. 이를 통해 자원의 회수 및 자식 프로세스의 종료 상태 값을 얻을 수 있다.
#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) { // fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { // child (new process)
printf("hello, I am child (pid:%d)\n", (int) getpid());
} else { // parent goes down this path (main)
int wc = wait(NULL);
printf("hello, I am parent of %d (wc:%d) (pid:%d)\n",rc, wc, (int) getpid());
}
return 0;
}
마지막으로, exec() 시스템 콜
exec() 계열의 시스템 콜은 프로세스가 새로운 프로그램을 실행하게 해 준다. exec() 호출은 현재 프로세스의 이미지를 새로운 프로그램의 이미지로 교체한다. 이는 프로세스의 메모리 내용을 완전히 새로운 프로그램으로 바꾸는 것을 의미한다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.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) { // fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { // child (new process)
printf("hello, I am child (pid:%d)\n", (int) getpid());
char *myargs[3];
myargs[0] = strdup("wc"); // program: "wc" (word count)
myargs[1] = strdup("p3.c"); // argument: file to count
myargs[2] = NULL; // marks end of array
execvp(myargs[0], myargs); // runs word count
printf("this shouldn’t print out");
} else { // parent goes down this path (main)
int wc = wait(NULL);
printf("hello, I am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int) getpid());
}
return 0;
}
왜, 이런 API를?
운영 체제의 핵심 기능 중 하나는 프로세스 관리이다. 프로세스는 운영 체제 상에서 실행 중인 프로그램의 인스턴스로, 각각 고유한 주소 공간과 시스템 자원을 할당받는다. 이러한 프로세스들을 효율적으로 생성, 실행, 관리, 종료하는 것은 시스템의 안정성과 성능에 직접적인 영향을 미친다. 이를 위해 운영 체제는 fork(), wait(), exec()와 같은 프로세스 관리 API를 제공한다.
복잡한 시스템의 단순화fork(), wait(), exec()와 같은 API들은 복잡한 멀티프로세싱 시스템을 구축할 때 필수적이다. 이들 API를 사용함으로써 개발자는 새로운 프로세스를 생성하고(fork()), 프로세스의 실행을 조정(wait()), 그리고 새로운 프로그램을 실행(exec())할 수 있다. 이 과정에서, 각 API는 복잡한 내부 작업을 추상화하고 개발자에게 단순화된 인터페이스를 제공한다. 결과적으로, 개발자는 운영 체제의 복잡한 내부 메커니즘을 자세히 알지 못해도 프로세스 관리 기능을 쉽게 구현할 수 있다.
멀티태스킹과 병렬 처리 지원컴퓨팅 환경은 멀티태스킹과 병렬 처리를 필요로 한다. fork()를 사용하여 프로세스를 복제하고, exec()로 새로운 작업을 실행시키며, wait()으로 자식 프로세스의 실행 완료를 동기화함으로써, 개발자는 여러 작업을 동시에 처리할 수 있는 애플리케이션을 만들 수 있다. 이는 웹 서버와 같이 동시에 여러 요청을 처리해야 하는 애플리케이션에서 특히 중요하다.
자원 관리 및 장애 격리프로세스 API를 사용하면 프로세스 간의 자원 공유와 통신을 정교하게 관리할 수 있다. 예를 들어, fork() 후 exec()를 사용하면, 자식 프로세스는 부모 프로세스로부터 독립된 메모리 공간을 할당받게 되며, 이는 장애 격리(fault isolation)를 가능하게 한다. 하나의 프로세스에서 발생한 문제가 다른 프로세스에 영향을 미치지 않도록 하는 것이다. 이러한 장애 격리 메커니즘은 시스템의 안정성과 보안을 향상한다.
효율적인 프로세스 관리wait() 시스템 콜은 부모 프로세스가 자식 프로세스의 종료를 기다리게 함으로써, 자식 프로세스가 시스템 자원을 반환하고 종료 상태를 부모에게 알리는 과정을 관리한다. 이는 프로세스가 시스템 자원을 낭비하지 않고 효율적으로 활용하도록 보장한다. 프로세스의 정상 종료 및 비정상 종료를 관리하는 것은 시스템의 성능과 안정성을 유지하는 데 중요하다.
'Deep Dive > OS' 카테고리의 다른 글
[OSTEP] 스터디 2주차 - 가상화의 세계 part.1 (0) | 2025.09.08 |
---|---|
[OSTEP] 스터디 1주차 - 아주 쉬운 세가지 이야기 (1) | 2025.09.01 |