article thumbnail image
Published 2020. 11. 28. 16:27

[ 2020 2학기 / 9주차 ]

 

 

1. 프로세스 이미지

  1.1 프로세스

  • 프로세스는 실행중인 프로그램이다.
  • 프로그램 실행을 위해서는 프로그램의 코드, 데이터, 스택, 힙, U-영역 등이 필요하다.
  • 프로세스 이미지(구조)는 메모리 내의 프로세스 레이아웃이다.
  • 프로그램 자체가 프로세스는 아니다.

 

[프로세스 이미지]

  • 텍스트(코드)
    프로세스가 실행하는 실행 코드를 저장하는 영역
  • 데이터
    프로그램 내에 선언된 전역 변수 및 정적 변수 등을 위한 영역

  • 동적 메모리 할당을 위한 영역
  • 스택
    함수 호출을 구현하기 위한 실행시간 스택을 위한 여역
  • U-영역
    열린 파일의 파일 디스크립터, 현재 작업 디렉터리 등과 같은 프로세스의 내부 정보

 

 

  1.2 size 명령어

$ size [실행파일]
실행파일의 각 영역의 크기를 알려준다. 실행파일을 지정하지 않으면 a.out를 대상으로 한다.

 

 

 

 

 

2. 프로세스 ID

  2.1 쉘의 명령어 처리과정

쉘의 명령어 처리과정

 

 

  2.2 프로세스 ID

  • 각 프로세스는 프로세스를 구별하는 번호인 프로세스ID를 갖는다.
#include  <unistd.h>

int getpid( );
프로세스의 ID를 반환한다.

int getppid( );
부모 프로세스의 ID를 반환한다.

예)

  • 프로그램 13.1 프로세스 ID

#include <stdio.h>

#include <unistd.h>

int main()

{

    printf("Hello !\n“);

    printf("나의 프로세스 번호 : [%d] \n", getpid());

    printf("내 부모 프로세스 번호 : [%d] \n", getppid());

    system(“ps”);

}

  • 실행결과

$ hello &

Hello !

나의 프로세스 번호 : [16165]

내 부모 프로세스 번호 : [9045]

PID TTY TIME CMD

9045 pts/3 00:00:00 bash

16165 pts/3 00:00:00 hello

16169 pts/3 00:00:00 ps

 

 

 

 

 

3. 프로세스 생성

  3.1 프로세스 생성

  • fork() 시스템 호출
    부모 프로세스를 똑같이 복제하여 새로운 자식 프로세스를 생성
#include <unistd.h>
pid_t fork(void);
새로운 자식 프로세스를 생성한다. 자식 프로세스에게는 0을 반환하고 부모 프로세스에게는 자식 프로세스 ID를 반환한다.

 

  • fork()는 한 번 호출되고 두 번 리턴한다.
  • 자식 프로세스에게는 0을 리턴하고 부모 프로세스에게는 자식 프로세스 ID를 리턴한다.
  • 부모 프로세스와 자식 프로세스는 병행적으로 각각 실행을 계속한다.

 

[프로그램 13.2 프로세스 생성]

#include <stdio.h>

#include <unistd.h>

 

/* 자식 프로세스를 생성한다. */

int main()

{

    int pid;

    printf("[%d] 프로세스 시작 \n", getpid());

    pid = fork();

    printf("[%d] 프로세스 : 반환값 %d\n", getpid(), pid);

}

 

[실행결과]

    [15065] 프로세스 시작

    [15065] 프로세스 : 반환값 15066

    [15066] 프로세스 : 반환값 0

 

 

  3.2 부모-자식 프로세스

fork() 호출 후에 리턴값이 다르므로 이 리턴값을 이용하여 부모 프로세스와 자식 프로세스를 구별하고 서로 다른 일을 하도록 할 수 있다.

 

예)

pid = fork();

if ( pid == 0 )

{ 자식 프로세스의 실행 코드 }

else

{ 부모 프로세스의 실행 코드 }

 

 

[프로그램 13.3 자식 프로세스 생성]

#include <stdlib.h>

#include <stdio.h>

#include <unistd.h>

/* 부모 프로세스가 자식 프로세스를 생성하고 서로 다른 메시지를 프린트 */

int main()

{

    int pid;

    pid = fork();

    if (pid ==0) { // 자식 프로세스

        printf("[Child] : Hello, world pid=%d\n“, getpid());

    }

    else { // 부모 프로세스

        printf("[Parent] : Hello, world pid=%d\n", getpid());

    }

}

 

[실행결과]

    [Parent] : Hello, world ! pid=15065

    [Child] : Hello, world ! pid=15066

 

 

  3.3 프로세스 기다리기: wait()

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
자식 프로세스 중의 하나가 종료할 때까지 기다린다. 자식 프로세스가 종료하면 종 료코드가 *status에 저장된다. 종료한 자식 프로세스의 ID를 반환한다.

 

 

 

 

 

4. 프로그램 실행

  4.1 프로그램 실행: exec()

• 프로세스가 exec() 호출을 하면, 그 프로세스 내의 프로그램은 완전히 새로운 프로그램으로 대치 

• 새 프로그램의 main()부터 실행이 시작한다.

• exec() 호출이 성공하면 리턴할 곳이 없어진다.

• 성공한 exec() 호출은 절대 리턴하지 않는다.

#include <unistd.h>
int execl(char* path, char* arg0, char* arg1, ... , char* argn,NULL)
int execv(char* path, char* argv[ ])
int execlp(char* file, char* arg0, char* arg1, ... , char* argn,NULL)
int execvp(char* file, char* argv[ ])
호출한 프로세스의 코드, 데이터, 힙, 스택 등을 path가 나타내는 새로운 프로그램으로 대치 한 후 새 프로그램을 실행한다. 성공한 exec( ) 호출은 리턴하지 않으며 실패하면 -1을 리턴 한다.

 

[프로그램 13.4 프로그램 실행 예]

#include <stdio.h>

#include <unistd.h>

 

/* echo 명령어를 실행한다. */

int main( )

{

    printf("시작\n");

    execl("/bin/echo", "echo", "hello", NULL);

    printf("exec 실패!\n");

}

 

[실행결과]

    시작

    hello

 

 

  4.2 쉘의 명령어 처리 원리

보통 fork() 호출 후에 exec() 호출. 새로 실행할 프로그램에 대한 정보를 arguments로 전달한다.

• exec() 호출이 성공하면 자식 프로세스는 새로운 프로그램을 실행하게 되고 부모는 계속해서 다음 코드를 실행하게 된다.

 

int pid, child, status;

pid = fork();

if (pid == 0 ) {

    exec(arguments);

    exit(1);

} else {

    child = wait(&status);

}

 

[프로그램 13.5 실행 예]

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

/* 자식 프로세스를 생성하여 echo 명령어를 실행한다. */

int main( )

{

    int pid, child, status;

    printf("부모 프로세스 시작\n");

    pid = fork();

    if (pid == 0) {

        execl("/bin/echo", "echo", "hello", NULL);

        fprintf(stderr,"첫 번째 실패");

        exit(1);

    }

    else {

        child = wait(&status);

        printf("자식 프로세스 %d 끝\n", child);

        printf("부모 프로세스 끝\n");

    }

}

 

[실행결과]

    부모 프로세스 시작

    hello

    자식 프로세스 15066 끝

    부모 프로세스 끝

 

 

 

 

 

5. 프로그램 실행과정

  5.1 프로그램 실행 시작

  • exec 시스템 호출
    C시작 루틴에 명령줄 인수와 환경 변수를 전달하고 프로그램을 실행시킨다.
  • C시작 루틴(start-up routine)
    main 함수를 호출하면서 명령줄 인수, 환경 변수를 전달
    실행이 끝나면 반환값을 받아 exit 한다.

 

  5.2 명령줄 인수/환경 변수

int main(int argc, char *argv[]);
argc : 명령줄 인수의 수
argv[] : 명령줄 인수 리스트를 나타내는 포인터 배열

[프로그램 13.6 명령줄 인수 예]

#include <stdio.h>

/* 모든 명령줄 인수를 프린트한다. */

int main(int argc, char *argv[])

{

    int i;

    for (i = 0; i < argc; i++) /* 모든 명령줄 인수 프린트 */

        printf("argv[%d]: %s \n", i, argv[i]);

    return 0;

}

 

[실행결과]

    $ printargv hello world

    argv[0]: printargv

    argv[1]: hello

    argv[2]: world

 

 

 

 

 

6. 시스템 부팅과 프로세스

  6.1 시스템 부팅

• 시스템 부팅은 fork/exec 시스템 호출을 통해 이루어진다.

 

swapper(스케줄러 프로세스) 커널 내부에서 만들어진 프로세스로 프로세스 스케줄링을 한다.
init(초기화 프로세스) /etc/inittab 파일에 기술된 대로 시스템을 초기화
서비스 데몬 프로세스 서비스들을 위한 데몬 프로세스들이 생성된다. 예: ftpd
getty 프로세스 로그인 프롬프트를 내고 키보드 입력을 감지한다.
login 프로세스 사용자의 로그인 아이디 및 패스워드를 검사
shell 프로세스 시작 파일을 실행한 후에 쉘 프롬프트를 내고 사용자로부터 명령어를 기다린다.

 

 

  6.2 프로세스 트리 출력

$ pstree
실행중인 프로세스들의 부모, 자식 관계를 트리 형태로 출력한다.

'Study > LINUX' 카테고리의 다른 글

[2020-2 리눅스 실습] 8주차  (0) 2020.11.22
[2020-2 리눅스 이론] 8주차  (0) 2020.11.22
[2020-2 리눅스 실습] 7주차  (0) 2020.11.14
[2020-2 리눅스 이론] 7주차  (0) 2020.11.14
[2020-2 리눅스 이론] 6주차  (0) 2020.11.08
복사했습니다!