개발👩‍💻/시스템프로그래밍

리눅스 프로세스 관리(10-1)

gigibean 2021. 6. 5. 00:12
728x90

프로세스라고 하는 것은 실행중 상태에 있는 프로그램을 말한다.

c로 프로그램을 짰다고 하면 컴파일 해서 기계어로 된 실행 파일을 만들었다. 파일 형태로 디스트에 저장된다.

그 프로그램을 실행시켜 실행중인 상태에 있는 것을 프로세스라고 한다.

 

하나의 프로그램을 동시에 여러번 실행히킬 수 있는데, 두개의 프로세스로써 따로따로 실행될 수 있다.

 

이런 프로세슬르 실행하는 방법이 있다.

유닉스에서 명령을 내려서 실행시키면, 로그인을 했을 때 쉘프로세스가 실행이된다.

쉘프로세스가 프롬프트를찍어서 명령어를 입력하게 하고 입력하면 명령어를 실행시키기 위해 새로운 프로세스, 자식 프로세를 하나 만든다. 그래서 자식 프로세스에게 프로그램을 실행하게 만든다. 프로그램이 실행되는 동안에는 프롬프트가 생기지 않는다. 실행을 마치고 없어지게 되면 쉘프로세스는 프롬프트를 직어서 다름 명령어를 운영하도록 한다. 

이런식으로 새로운 프로세스를 만들 수 있고,

 

이런식으로 세미콜론(;)을 붙이고 다른 명령어가 나오게 하는경우가 있는데 이것은

쉘에서 a.out이라는 명령을내렸으면, 이 프로그램 실행이 끝나면 프롬프트가 떨어져서 b.out이라는 명령어를 내릴 수 있겠다.

a.out이 오래 걸리는 프로세스라면, 이것을 마냥 기다렸다가 프롬프트가 떨어지면 다시 명령어를 입력하는 불편한 상황을 대비하기위해 여러개 명령어를 세미콜론으로 구분하여 순차적으로 프로그램이 실행될 수 있게 하기 위함이다.

명령어를 한줄에 입력하고 순차적으로 사용할 수 있다.

 

그런데 이제 이런식으로 프로그램을 실행시켰을 때 이 프로그램을 실행시키기위해 만들어진 프로세스를 foreground process라고 한다. 명령을 내리면서 두에 &엔퍼센트를 붙일 수 있는데, 이는 이프로세스를 백그라운트 프로세스로 돌리라는 명령어다. 

이는 쉘프로세스가 있고여기에 명령을 내리게 되면 자식 프로세스를 만든다. 자식 프로세스가 프로그램을 실행시키게 되는데 엔퍼센트를 넣어서 명령어를 실행시키면 백그라운드, 이 프로세스가 종료되지 않아도 프롬프트를 찍어주게 된다. 그렇게되면 다음 명령을 또 내릴 수 있게 된다.

백그라운드 프로세스가 자식프로세스로 돌아가고 있고, 다음 명령어에 대한 프로세스가 병렬로 자식 프로세스로 생성되어 따로 돌아가게 할 수 있는 것이다.

프로세스를 계속해서 병렬적으로 실행시킬 수 있고 이렇게 &로 실행시킨 프로세스 2개 뒤에 새로운 명령어를 입력하면

2개의 백그라운드 프로세스와 한개의 포어그라운드 프그라운드 로세스가 돌아가게 된다.

그런데 포어그라운드 프로세스는 그 프로세스가 끝나야 그 다음 프롬프트가떨어지기 때문에 또다른 프로세스를 병렬로 또 만들 수 없다.  그렇기 때문에 포어그라운드에서 돌릴 수 있는프로세스는 1개밖에 없다.

반대로 백그라운드에서 돌릴 수 있는 프로세스는 1개 이상이다.

 

서로 협력하는 두개이상의 프로세스 생성하기

서로 협력하는 두개이상의 프로세스를 만들기 위해서는 파이프(|)를 사용한다.

 

$ ls /bin | wc -w

라는 명령어를 입력하여 파이프로 연결 시켰다.

이렇게 파이프로 연결시키면 파이프 앞에 있는 프로세스 실행하고 실행 결과 출력될 내용을 표준 출력으로 출력하지 않고 그 내용을 그 다음 프로그램의 입력으로 다음 프로세스에게 넘겨준다.

여러개 만들 수있고, 화면에 나올 출력을 파이프 다음 프로세스가 입력으로 받고 마지막 명령어가 표준 출력으로 나오게 된다.

 

쉘프로세스

쉘 프로세스는 로그인했을 때 가장 먼저 보게되는 프로세스

일반적으로 프로세스는 여러가지 속성을 가지게 된다.

예를들어 umask 라는 속성값을 갖고 이 값을변경시키기 위한 umask()라는 시스템 콜이 있었다.

그 다음에 커런트 워킹 디렉토리를 변경하기 위한 시스템콜 chdir() 도 있었다.

uid 라고 누가 그 프로그램을 실행시켰는지 알 수 있는 시스템콜도 있었다.

 

쉘에서 어떤 명령을 내려 실행시키면 그 명령을 실행시키기 위한 자식프로세스를 생성하는데, 자식 프로세스도 이러한 속성을 갖게된다. 모든프로세스 이런 속성 다 갖는다.

자식 프로세스의 값은 부모 프로세스의 값을 상속한다.

그래서 위 umask, uid 등도 부모 프로세스의 값을 상속받는다.

그런데 부모 프로세스로 부터 물려받지 않는 것들도 있는데, pid : 이프로세스이 아이디가 무엇인지

따라서 부모,자식이 같은 값을 가지면 안되니 물려받지 않는다.

사용자가 명령을 실행시키면서 만들어지는 프로세스들을 유저 프로세스, 사용자가 만든 프로세스라고 한다.

시스템 프로세스라는 반대되는 개념이 있다. 운영체제가 시스템을 관리하기위해서 이런 프로세스를 실행하게 된다.

 

파일의 소유자와 실행시키기 위한 프로세스의 유저는 아무런 관련이 없다.

그래서 파일의 소유자와 프로세스의 소유자는 다를 수 있다.

 

foreground / background process

포어그라운드 프로세스는 한 터미널에서 하나만 존재할 수 있다.

터미널 창을 두개 열었다고 하면 터미널 창 하나마다 하나의 쉘프로세스가 돌아가는데

따로따로 쉘프로세스가 돌아간다.

터미널마다 하나의 프로세스만이 포어그라운드 프로세스가 될 수 있다.

포어그라운드는 하나가 끝나야 다음 명령어가 돌아갈 수 있기 때문에 더이상 추가적으로 만들 수 없다. 그래서 한 터미널마다 한 프로세스만 포어그라운드 프로세스가 될 수 있다. 

포어그라운드 프로세스만이 표준 입력을 받을 수 있다.

예를들어 쉘에서 cat이라는 명령을 내렸다고 하면 이는 포어그라운드에서 돌아가고 있기 때문에 hello라고 입력하면 hello라고 출력되게 된다.

키보드에서 입력을 하게 되면 프로그램이 받아서 출력을 한다. 그런데 만약에 명령어에 &를 붙여 백그라운드에서 돌아가게 한다면 표준입력을 받을 수 없게 된다.

포어그라운드 프로세스 하나만 받을 수 있기때문에 백그라운드 프로세스에서 입력을 받게 되면 정상적으로돌아갈 수 없기 때문에 이런 경우에는 프로세스가 일시정지되게 된다.

 

포어그라운드 프로세스 하나만 받을 수있고 백그라운드 프로세스는 여러개 있을 수 있지만 입력은 받을 수 없다.

 

표준 출력 같은 경우 두 프로세스 할 수 있다.

따라서 쉘에서 어떤 프로그램을 실행시켰다면

터미널창에 나오는 결과는 모든 출력 결과가 섞여서 나오게 된다.

백그라운드, 포어그라운드 표준 출력장치로 출력되게 된다.

 

그다음에 한 터미널 창에서 포어그라운드 프로세스는 1개밖에 없기 때문에 하나의 터미널 창에서 여러 프로세스가 돌아가고 있다고 한다면 하나를 제외한 나머지 프로세스는 백그라운드 프로세스이다.

 

포어그라운드, 백그라운드 프로세스를 구분하는 것은 확정적인 것이 아니다

&를 사용하면 백그라운드 프로세스임이 확정이 된다.

그리고 아무것도 붙이지 않고 하나의 프로세스만 돌아간다면 포어그라운드일 것이다. 그러나 이것들이 왜 확정적이지 않다고 하냐면 이것간의 상호 왔다갔다 하게 할 수 있다 두개의 프로세스를 바꿀수있기 때문에 구분이 확정적인 것은 아니다.

 

#include <stdio.h>
#include <unistd.h>
int main()
{
	int i;
	for (i = 0; i < 100; i++) {
	sleep(6);
	printf(“i = %d\n”, i);
}
return 0;
}

위와 같은 프로그래밍을 짜서 6초에 한번씩 내용을 출력하는 간단한 프로그램이다

이 프로그램을 컴파일해서 실행을 시킨다.

 

여기서 관련 명령어들이 있다.

- bg: background

- fg: foreground

위 명령어들을 가지고 상호 전환이 가능하다.

$ ./a.out > a&
[1] 5044
$ ./a.out > b&
[2] 5045
$ jobs
[1]- Running ./a.out > a &
[2]+ Running ./a.out > b &
$ ./a.out > c
Ctrl-Z
[3]+ Stopped ./a.out > c
$ jobs
[1] Running ./a.out > a &
[2]- Running ./a.out > b &
[3]+ Stopped ./a.out > c

1. 위 명령어와 같이 .a.out을 실행시키고 백그라운드 프로세스에 결과를 a라는 파일로 리다이렉션 시켰다 &를 붙였으니 백그라운드 프로세스이다.

실행시킨 후 나온 숫자는 실행되고있는 프로세스(a&)의 pid를 의미한다.

ps를 가지고 현재 실행되고 있는 프로세스의 id가 무엇인지 확인할 수 있다.

프로세스의 아이디를 보여주고 있고

앞에 있는 [1] 는 job번호이다.

 

2. 또한번실행시켜 b&로 보내면

2번 job에 프로세스 id를 나타낸다.

 

3. jobs 명령어는 job들이 무엇이 있고, 어떤 게 돌아가고 멈춰있는지 job의 현황을 볼 때 사용된다. 

두개의 프로세스를 백그라운드에서 돌리고 있으니 그 현황을 볼 수 있다.

 

또 프로그램을 실행시키면 c는 다로 &가 없으니까 foreground에서 실행시키는 것이다.

여기서 돌리면 6초에 한번식 ㄸㄹ리는 프로그램이었기 때문에 출력은 fore,back 둘다 된다.

여기서 지정된 파일들로 모두 출력되게 했기 때문에 해당 터미널에는 따로 출력되지 않고 지정된 파일에 출력되게 된다. 화면상에 나오는 것은 아무것도 없이 이번 명령어는 foreground에서 돌아가고 있기 때문에 프롬프트가 안떨어진다.

다른 명령도 낼 수 없는 상태가 된다.

ctrl+z눌러 프로세스를 일시정지 시킨다. (ctrl+c누르면 정지)

그래서 세번째 실행시킨 3번 job이 일시정지 된다. stopped 된다.

 

4. jobs 를 통해서 돌고 있는, 멈춰있는 프로세스를 볼 수 있다.

$ bg %3
[3]+ ./a.out > c &
$ jobs
[1] Running ./a.out > a &
[2]- Running ./a.out > b &
[3]+ Running ./a.out > c &
$ fg %1
./a.out > a
Ctrl-Z
[1]+ Stopped ./a.out > a
$ jobs
[1]+ Stopped ./a.out > a
[2] Running ./a.out > b &
[3]- Running ./a.out > c &
$ kill %2

1. bg라는 명령어를 가지고 job들중에서 내가 지정한 job, %3이라고 하면 3번 job을 의미한다. 

해당 job을 백그라운드로 전환시키라는 명령어이다.

뒤에 엠퍼센트 없이 포어그라운드로 실행시켰다가  ctrl+z를 눌러 일시정지 시켰는데, 이 프로세스를 백그라운드로 전환하라는 명령어이다.

그래서 해당 명령에 따른 출력을 보면 해당 job 명령어 뒤에 &가 붙은 것을 볼 수 있다.

 

2. jobs 로 확인해보면 3개의 job이 다 백그라운드에서 돌고 있는 것을 봤다. 

모두 백그라운드에서돌고있기 때문에 프롬프트가 떨어진다.

 

3. 1번job을 fg 명령어를 통해서 foreground로 변환한다.

1번 job은 백그라운드로 돌고 있으니 fore로 변환하면 실행중인 foreground process이기 때문에 프롬프트가 떨어지지 않는다. 그래서 ctrl+z를 이용하여 일시정지 시킨다.

 

4. kill 명령은 -9를 이용해서 해당 프로세스 id로 프로세스를 죽였던 것이 있었다.

job리스트에서 번호를 주고 해당 프로세스를 죽이라는 명령을 사용할 수있다.

반응형