본문 바로가기
2022-2/시스템 프로그래밍

9장 프로세스 제어

by 철없는민물장어 2022. 11. 16.
728x90
반응형
9.1 프로세스 생성

fork()시스템 호출

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

pid_t fork(void);

새로운 프로세스를 생성하는 유일한 방법이다.

fork()시스템 호출 시 부모 프로세스를 똑같이 복제하여 새로운 자식 프로세스를 생성한다.

자식 프로세스는 pid를 제외하고 모든 것(코드,데이터,스택,힙 등)이 똑같다.

 

fork()는 pid를 반환하는데, 

부모 프로세스는 자식 프로세스의 id를 반환하고

자식 프로세스에서는 0을 리턴한다

(부모, 자식 총 2번 리턴함)

 

fork()이후 부모와 자식은 병행적으로 각각 실행을 계속한다.

#include <stdlib.h>
#include <stdio.h>

int main()
{
	int pid;
    pid=fork();
    if(pid==0)//자식 프로세스
    {
    	printf("난 자식임 pid=%d",getpid());
    }
    else//부모
    {
    	printf("난 부모야, pid는 %d야",getpid());
    }
}

(정말 참고로 자식의경우 fork()리턴값이 0인거지 pid가 0인게 아니다)

 

(추가)

자식은 부모의 fd 테이블을 복사하므로 같은 파일 오프셋을 공유한다.


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

 

자식 프로세스 중의 하나가 끝날 때까지 기다린다.

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);//특정 pid프로세스의 종료 대기

실행이 끝난 자식 프로세스의 종료코드를 status에 저장하고, 해당 자식프로세스 pid를 리턴함.

 

#include <unistd.h> ...

int main()
{
	int pid,child,status;
    printf("[%d] 부모 프로세스 시작\n",getpid());
    pid=fork();
    if(pid==0)
    {
    	printf("[%d]자식 프로세스 시작 \n",getpid());
        exit(1);
    }
    child=wait(&status);//자식 프로세스가 끝나기를 기다리고 자식pid를 반환받아 child에 저장
    printf("[%d] 자식 프로세스 %d 종료\n",getpid(),child);//부모가 수행하게됨.
    printf("종료코드: %d",status>>8);
}

9.2 프로그램 실행

fork()이후 자식 프로세스에게 새 프로그램을 실행 시켜야 한다.

이 때 exec()시스템호출을 사용한다.

 

exec()는 프로세스 내의 프로그램을 새 프로그램으로 대치한다.

 

pid는 그대로,

PC는 처음으로 올라간다.

프로세스 내의 프로그램이 완전히 새로운 프로그램으로 대치되므로,

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[]);

exec 

뒤에 l 이 붙는 경우 : 인자를 하나하나 작성해서 넘김.(arg0, arg1, . . . .NULL) 꼭 NULL까지 입력할 것 주의.

뒤에 v가 붙는 경우 : 인자를 리스트로 넘김(argv)

뒤에 p가 붙는 경우 : 명령어 경로가 아닌 프로그램 이름을 주고, 환경변수 PATH에서 찾음. (그냥 명령어이름 넘기면됨)

예시 코드)

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

int main()
{
	printf("시작\n");
    execl("/bin/echo", "echo", "hello", NULL);
    printf("exec 실패");
}

exec 실행에 성공하면 

"exec 실패" 부분은 실행되지 않고,

 

시작

hello

 

의 결과가 나오게 된다.

더보기

execv로는 argv를 넘겨주고,

./a.out (명령어제외) 인자1 인자2 . . .

이렇게 실행시키면 정상작동한다.

(예시 오류: argv[0]에는 ./a.out이 들어있으므로 두번째 인자는 &argv[1]로 주는것이 마땅함

 

execl은 코드에서 명령어, 인자1 인자2. . .NULL을 줘야한다.

./a.out 만 입력하면 코드에 인자 입력했던 대로 명령어가 실행된다.

 

뒤에 p가 붙은 것은 맨 앞 인자로 명령어파일명을 입력하면 된다

ls의 경우.. 그냥 "ls"로 넣어주면 된다.

 

 


fork()를 수행하고 exec를 연속으로 수행하는 것은 상당히 번거롭다.

이러한 과정을 자동으로 수행하는 C라이브러리 함수 system() 이 있다.

#include <stdlib.h>
int system(const char *cmdstring);

예를 들어 system("ls -asl");을 하면 자식 프로세스를 생성하고 /bin/sh로 하여금 ls -asl이 수행되도록 한다.

 


9.4 프로세스 그룹

프로세스 그룹은 여러 프로세스들의 집합이다.

보통 부모 프로세스가 생성하는 자손 프로세스들은 부모와 같은 프로세스 그룹에 속한다.

 

프로세스 그룹 리더는 프로세스 GID와 PID가 동일하다

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

int setpgid(pid_t pid, pid_t pgid);
//프로세스 pid의 프로세스 그룹 id를 pdid로 설정한다. 성공시 0, 실패시 -1 반환.

이 때 pid와 pgid가 같은 경우 => 새로운 그룹을 생성하고, 그 그룹의 리더가 됨

pid와 pgid가 다른 경우 => pgid 그룹으로 이동

pid가 0인 경우 => 호출자의 pid값을 그대로 사용

pgid가 0인 경우 => pid가 새로운 그룹 리더가 됨.

 

호출자가 새로운 프로세스 그룹을 생성하고 그룹의 리더가 되는 방법은

setpgid(getpid(),getpid())혹은

setpgid(0,0)으로 할 수 있다

 


9.5 시스템 부팅

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

728x90
반응형

'2022-2 > 시스템 프로그래밍' 카테고리의 다른 글

백도어  (0) 2022.12.06
계정과 권한/패스워드 크래킹  (0) 2022.11.22
10장 메모리 관리  (0) 2022.11.11
8장 프로세스  (1) 2022.11.08
5. 파일 시스템  (0) 2022.11.02

댓글