[운영체제]processes

정태규·2023년 4월 13일
0

운영체제

목록 보기
2/20

OS는 process,memory,storage를 가상화 시켜준다.

덕분에 한정된 메모리 공간안에서 많은 process들을 돌릴 수 있고, 여러가지 일들을 수행할 수 있다.

process란?

실행중인 프로그램 instance 하나 하나를 process라고한다.
정확하게 말하면, .exe 파일을 메모리로 가져온것(인스턴스 형태)을 말한다.
인스턴스이기 때문에 여러개 만들 수 있다.
참고로, 여러개 만들었을때 이 프로세스들을 구분하는 것이 PID(process ID)이다.

process들은 Active하고 dynamic한 entity이다.

한 실행 파일을 여러 유저가 동시에 실행한다고 가정해보자.(ex) 게임)

실행을 한 모든 컴퓨터는 같은 실행 파일을 가지는 process들을 띄울것이다.
이 process들은 모두 PID가 다르고, 밑의 그림과 같은 메모리들이 모든 프로세스마다 각각 할당될 것이다.

위에서 말했듯이, 각각의 process 들은 그들 자신의 메모리 주소 공간을 가진다.

  • program은 code(text section)에 있다.

    program counter라고 불리는 register가 현재 실행중인 instruction을 code에서한 byte씩 가리킨다.

  • Data section은 global variable을 가지고 있다.

  • stack은 temporary data를 가진다.

    함수 파라미터, return 주소값, 지역 변수등이다.
    stack pointer register에 의해서 가리킨다.

  • heap은 run time동안 동적으로 할당된 메모리를 가진다.

process 상태

  • new : process가 만들어지고 있는 중
  • ready: process가 processor(CPU)에 할당되기 위해 기다리는 중
  • running: instruction이 실행되고 있는중
  • blocked: process가 I/O(interrupt 발생)가 끝나길 기다리는 중(CPU를 안쓰고 있는 0인상태(ex.)scanf 기다릴때))
  • exited: process 실행이 끝났다.
  • scheduled: proccess를 CPU에 넣고 돌린다.
  • De-scheduled: process를 running에서 ready상태로 바꾼다.

process Hierarchy

  • process(parent)는 다른 process(children)들을 만들 수 있다.
  • 형제 process들은 같은 부모 process들을 가진 children 이다.
  • tree구조이다.

fork()

  • 현재 process와 똑같은 process를 생성한다.(복제된다고 보면 됨.)

    부모의 모든 resource와 privilege를 상속받는다.(open file, UID 등등)
    child는 parent의 address space를 그대로 복제한다.

  • fork 된 두 process들은 instruction의 다음 라인을 계속해서 parallel하게 실행한다.

  • shell이나 GUI는 내부적으로 이러한 system call을 사용한다.

  • Return value:

    fork()가 성공하면, child process의 PID를 parent에게 return 하고, child는 0이 return 된다.
    실패 했을경우에는 -1을 parent에서 리턴한다.(child process가 만들어지지 않았을경우나, errno가 적절하게 설정되어 있지 않을 경우)

위에서 설명한 것처럼 parent의 주소가 child에게 그대로 복사된다.
물론, parent와 child는 별개의 주소 공간을 가진다.

✍️example

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	fork();
    
    printf("Hello world\n");
    return 0;
}

결과:
Hello world
Hello world

process가 두개 생겼기 때문에 두번 출력되었다.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	fork();
    fork();
    fork();
    
    printf("Hello world\n");
    return 0;
}

결과:
Hello world
Hello world
Hello world
Hello world
Hello world
Hello world
Hello world
Hello world

fork를 3번한다면??

fork를 한번 했을때 자식 하나가 생겨서 2개가 되었다.
한번더 fork를 하면 원래 부모 process와 아까 생긴 자식 process 둘다 자식 process가 생기기 때문에 4개가 된다.
한번더하면 8개가 된다.

따라서 8번 출력된다.

밑에 코드를 보자.

#include <stdio.h>
#include <unistd.h>
#include <stdio.h>

void forkexample(){
	pid_t pid;
    if((pid = fork()) == 0){ // child process
    	printf("I am %d, a child of %d\n",getpid(),getpid());
    }else{ // parent
    	printf("I am %d, a parent of %d\n",getpid(), pid)
    }
}

int main(int argc,cons char *argv[]){
	forkexmaple();
    return 0;
}

fork()를 했을때, child process는 0을 return 받고 parent process는 child process의 pid를 return 받는다고 했다.
그래서 위 코드에서 pid == 0 이면 child process이고 0보다 크면 parent process라는 것을 알 수 있다.

참고로, getpid()는 현재 process의 pid를 알려준다.
위에서 자식 process에서는 자식 process의 pid를 알려줄것이고,
부모 process에서는 부모 process의 pid를 알려줄 것이다.

exac() family

  • 현재 process를 아예 지우고 새로운 process를 생성한다.
  • 현재 process의 address space까지 아예 지우고 새로운 process를 만드는 것이다.
  • windows: CreateProcess() = fork() + exec()
  • 앞에서 fork를 배운 이유를 알 수 있다. fork를 사용하지 않고 exec()을 사용했으면, 현재 process가 사라져 버려서 원하는 프로그램을 만들 수 없다.
  • exac 함수는 여러가지가 있다.

    🎈 execl()
    🎈 execlp()
    🎈 execle()
    🎈 execv()
    🎈 execvp()
    🎈 execvpe()

  • l:Comma-sepearated arguements
  • v:Vectored (array of strings) arguments
  • p:Find executable with PATH environment variable
  • e:Specify environment variables

예를들어,


bpid_t ash pint *statusrocess 두개가 있다. 여기서 vim을 실행하게 되면 bash가 사라지고 그자리에 vim 파일이 실행된다.

process Termination

  • exit()

    • process는 exit() 시스템 콜을 통해 OS에게 자기 자신을 종료해도 되는지 물어볼 수 있다.
    • OS는 프로세스의 resource를 회수한다.
    • main 함수에서 return -10을 준다면 system call을 통해서 main함수가 죽었다고 OS에 알려주고 OS는 전부다 날려버리고 exit_code =-10만 남긴다.
  • kill(),abort()

    • process는 다른 process들을 종료시킬 수 있다.
    • 신호를 통해 처리되는 비동기(asynchronous) 프로세스 간 통신 메커니즘이다.
  • pid_t wait(int *status)

  • wait() 시스템 콜은 child process가 종료될때까지 기다려준다.
    아까, fork를 했을때, child와 parent중 누가 먼저 실행될 지 모른다. wait()를 사용하면 child process가 끝날때 까지 기다려주고 정상 종료 시켜준다.
    만약 wait()로 정상종료 시켜주지 않는다면, 좀비 process로 메모리를 차지하고 있을 수도 있다.
  • 종료된 process의 pid와 status information을 return한다.
  • waitpid()

    • wait()와 비슷한 기능을 한다.
    • pid = waitpid(targetpid,&status,0);
    • pid = waitpid(-1,&target,0);
  • Zombie process

    • process가 종료되었지만, 해당 process의 부모나 다른 process가 wait()나 waitpid()를 호출하지 못해서 생긴다.
    • 만약, process가 죽어서 Exit_code로 남아있는데 아무도 찾아주지 않으면
      계속 메모리에 남아있다.
  • Orphan process

    • parent process가 wait()를 부르지 않고 먼저 죽어버린 경우
    • 몇몇 OS들은 cascading termination을 시작해서 Orphan을 남기지 않는다.
      *cascading termination: Orphan이 생기지 않도록 먼저 죽은 parent의 자식들까지 모두 죽인다.
    • UNIX나 LINUX에서는 init/systemd process(최초의 process)가 orphan process들을 입양한다. 그리고 주기적으로 wait()를 부른다. (reparenting)

Implementing Process

  • PCB(process Control Block) ,process descriptor, task control block

    🎈 각 PCB는 하나의 process를 나타낸다.
    🎈 process에 관한 모든 정보를 포함한다.

    • process state : running,wait,etc...
    • PID,PPID,process group,priority,...
    • Program counter(실행되고 있는 지점을 알려줌)
    • CPU register
    • CPU scheduling information
    • Memory-management information
    • Accounting information (CPU used,시작 부터 경과한 clock time,time limits)
    • I/O status information(I/O 장치들은 process에 할당된다, open files lilst)

0개의 댓글