시스템콜

김하영·2023년 5월 28일
0

운영체제

목록 보기
4/13

프로세스 생성과 제어를 위한 시스템콜

fork( ), exec( ), wait( )와 같은 것들은 Process 생성과 제어를 위한 System call

  • Process 생성 : fork, exec
  • Process 제어 :wait - Process (Parent)가 만든 다른 Process(child) 가 끝날 때까지 기다리는 명령어다.

fork()

새로운 프로세스를 생성할때 사용한다.

  • fork()를 호출하면 현재 프로세스의 복사본을 생성한다.
    • caller : parent, copy : child
    • 두 프로세스 모두 같은 코드를 갖게 된다(OS는 위와 똑같은 2개의 프로그램이 동작한다고 생각하고, fork()가 return될 차례라고 생각한다).
  • 두 프로세스모두 fork()를 호출하고 난 이후부터 진행된다.
  • 두 프로세스는 fork()에서 반환하는 값으로 구분할 수 있다.
    • child process : 0
    • parent process : child process의 pid 값
  • 두 프로세스는 서로 독립적이다 -> 따라서 각각의 프로세스는 서로의 상태에 관계없이 진행된다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    printf("pid : %d", (int) getpid()); // pid : 29146
    
    pid_t pid = fork();					
    
    if (pid < 0) {
        exit(1);						// (1) fork 실패
    }									
    else if (pid == 0) {					// (2) child 인 경우 (fork 값이 0)
        printf("child (pid : %d)", pid);
    }
    else {								// (3) parent case
        printf("parent (pid : %d)", pid);
    }
}

wait()

  • wait() 함수를 호출한 프로세스(parent)는 child 프로세스가 끝날때까지 기다린다.
    • parent는 wait()를 호출하고 기다린다.
    • child가 끝나면 parent는 진행을 재개한다.
  • child 프로세스가 재귀적으로 wait()함수를부르는걸 방지해야 한다.
  • 반환값은 종료된 child프로세스의 pid이다. -1이라면 child 프로세스가 없는 것이다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    printf("pid : %d", (int) getpid()); // pid : 29146
    
    pid_t pid = fork();					
    
    if (pid < 0) {
    	
        exit(1);						// (1) fork 실패
    }									
    else if (pid == 0) {					// (2) child 인 경우 (fork 값이 0)
    	sleep(3)
        printf("child (pid : %d)", pid);
        exit(0);
    }
    else {								// (3) parent case
    	int wc = wait(NULL);
        printf("parent (pid : %d)", pid);
    }
}

exec

  • 단순 fork()는 동일한 프로세스의 내용을 여러번 동작할때 사용한다.
  • child에서 parent와 다른 동작을 하고 싶을때는 exec를 사용한다.
  • 즉, fork()는 복사, exec는 대체!

exec가 실행되면,
execvp( 실행 파일, 전달 인자 ) 함수는, code segment 영역에 실행 파일의 코드를 읽어와서 덮어 씌운다.
씌운 이후에는, heap, stack, 다른 메모리 영역이 초기화되고, OS는 그냥 실행한다. 즉, 새로운 Process를 생성하지 않고, 현재 프로그램에 echo 프로그램을 실행한다. 그로인해서, execvp() 이후의 부분은 실행되지 않는다.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
    printf("pid : %d", (int) getpid()); // pid : 29146
    
    int rc = fork();					// 주목
    
    if (rc < 0) {
        exit(1);
    }									// (1) fork 실패
    else if (rc == 0) {					// (2) child 인 경우 (fork 값이 0)
        printf("child (pid : %d)", (int) getpid());
        char *myargs[3] = {"echo", "hello", "students",(char *)0}
        		// myargs[0] 내가 실행할 프로그램 이름
        		// myargs[1] 실행할 파일에 넘겨줄 argument
        		// myargs[2] end of array
        execvp(myarges[0], myargs);	
        printf("this shouldn't print out") // 실행되지 않음.
    }
    else {								// (3) parent case
        int wc = wait(NULL)				// 추가된 부분
        printf("parent of %d (wc : %d / pid : %d)", wc, rc, (int)getpid());
    }
}

fork()와 exec를 함께 수행하면 1개의 소스코드로 2개의 프로세스를 동작하도록 할 수 있다.

profile
백엔드 개발자로 일하고 싶어요 제발

0개의 댓글